Kafka為什麼這麼快?

来源:https://www.cnblogs.com/waynaqua/archive/2023/08/27/17660452.html
-Advertisement-
Play Games

Kafka 是一個基於發佈-訂閱模式的消息系統,它可以在多個生產者和消費者之間傳遞大量的數據。Kafka 的一個顯著特點是它的高吞吐率,即每秒可以處理百萬級別的消息。那麼 Kafka 是如何實現這樣高得性能呢?本文將從七個方面來分析 Kafka 的速度優勢。 - 零拷貝技術 - 僅可追加日誌結構 - ...


Kafka 是一個基於發佈-訂閱模式的消息系統,它可以在多個生產者和消費者之間傳遞大量的數據。Kafka 的一個顯著特點是它的高吞吐率,即每秒可以處理百萬級別的消息。那麼 Kafka 是如何實現這樣高得性能呢?本文將從七個方面來分析 Kafka 的速度優勢。

  • 零拷貝技術
  • 僅可追加日誌結構
  • 消息批處理
  • 消息批量壓縮
  • 消費者優化
  • 未刷新的緩衝寫入
  • GC 優化

以下是對本文中使用得一些英文單詞得解釋:

Broker:Kafka 集群中的一臺或多台伺服器統稱 broker
Producer:消息生產者
Consumer:消息消費者
zero copy:零拷貝

1. 零拷貝技術

零拷貝技術是指在讀寫數據時,避免將數據在內核空間和用戶空間之間進行拷貝,而是直接在內核空間進行數據傳輸。對於 Kafka 來說,它使用了零拷貝技術來加速磁碟文件的網路傳輸,以提高讀取速度和降低 CPU 消耗。下圖說明瞭數據如何在生產者和消費者之間傳輸,以及零拷貝原理。

Image from — https://blog.bytebytego.com/p/why-is-kafka-fast

步驟 1.1~1.3:生產者將數據寫入磁碟
步驟 2:消費者不使用零拷貝方式讀取數據

2.1:數據從磁碟載入到 OS 緩存

2.2:將數據從 OS 緩存複製到 Kafka 應用程式

2.3:Kafka 應用程式將數據複製到 socket 緩衝區

2.4:將數據從 socket 緩衝區複製到網卡

2.5:網卡將數據發送給消費者

步驟 3:消費者以零拷貝方式讀取數據

3.1:數據從磁碟載入到 OS 緩存

3.2:OS 緩存通過 sendfile() 命令直接將數據複製到網卡

3.3:網卡將數據發送到消費者

可以看到,零拷貝技術避免了多餘得兩步操作,數據直接從OS 緩存複製到網卡再到消費者。這樣做的好處是極大地提高了I/O效率,降低了CPU和記憶體的消耗。

推薦博主開源的 H5 商城項目waynboot-mall,這是一套全部開源的微商城項目,包含三個項目:運營後臺、H5 商城前臺和服務端介面。實現了商城所需的首頁展示、商品分類、商品詳情、商品 sku、分詞搜索、購物車、結算下單、支付寶/微信支付、收單評論以及完善的後臺管理等一系列功能。 技術上基於最新得 Springboot3.0、jdk17,整合了 MySql、Redis、RabbitMQ、ElasticSearch 等常用中間件。分模塊設計、簡潔易維護,歡迎大家點個 star、關註博主。

github 地址:https://github.com/wayn111/waynboot-mall

2. 僅可追加日誌結構

Kafka 中存在大量的網路數據持久化到磁碟(生產者到代理)和磁碟文件通過網路發送(代理到消費者)的過程。這一過程的性能會直接影響 Kafka 的整體吞吐量。為了優化 Kafka 的數據存儲和傳輸,Kafka 採用了一種僅可追加日誌結構方式來持久化數據。僅可追加日誌結構是指將數據以順序追加(append-only)的方式寫入到文件中,而不是進行隨機寫入或更新。這樣做的好處是可以減少磁碟 I/O 的開銷,提高寫入速度。

人們普遍認為磁碟的讀寫速度很慢,但實際上存儲介質(尤其是旋轉介質)的性能很大程度上取決於訪問模式。常見的 7,200 RPM SATA 磁碟上的隨機 I / O 的性能要比順序 I / O 慢 3 ~ 4 個數量級。此外,現代操作系統提供了預讀和延遲寫入技術,可以預先取出大塊的數據,並將較小的邏輯寫入組合成較大的物理寫入。因此,即使在快閃記憶體和其他形式的固態非易失性介質中,隨機 I/O 和順序 I/O 的差異仍然很明顯,儘管與旋轉介質相比,這種差異性已經很小了。

3. 消息批處理

Kafka 的高吞吐率設計的核心要點之一是批處理,即 Kafka 在消息發送端和接收端都引入了一個緩衝區,將多條消息打包成一個批次(Batch),然後一次性發送或接收。這樣做的好處是可以減少網路請求的次數,減少了網路壓力,提高了傳輸效率。

Kafka 的消息批處理優化主要涉及以下幾個方面:

發送端(Producer)

Kafka 的 Producer 只提供了單條發送的 send()方法,並沒有提供任何批量發送的介面。當調用 send()方法發送一條消息之後,無論是同步還是非同步發送,這條消息不會立即發送出去,而是先放入到一個雙端隊列中,然後 Kafka 使用一個非同步線程從隊列中成批發送消息。

Kafka 提供了以下幾個參數來控制發送端的批處理策略:

  • batch.size:指定每個批次可以收集的消息數量的最大值。預設是 16KB。
  • buffer.memory:指定每個 Producer 可以使用的緩衝區記憶體的總量。預設是 32MB。
  • linger.ms:指定每個批次可以等待的時間的最大值。預設是 0ms。
  • compression.type:指定是否對每個批次進行壓縮,以及使用哪種壓縮演算法。預設是 none。

接收端(Broker)

Kafka 的 Broker 在接收到 Producer 發送過來的批次後,不會把批次再還原成多條消息,而是直接將整個批次寫入到磁碟中。這樣做的好處是可以減少磁碟 I/O 的開銷,提高寫入速度。

Kafka 利用了操作系統提供的記憶體映射文件(memory mapped file)功能,將文件映射到記憶體中,使得對文件的讀寫操作就相當於對記憶體的讀寫操作。這樣就避免了用戶空間和內核空間之間的數據拷貝,也避免了系統調用的開銷。

消費端(Consumer)

Kafka 的 Consumer 在從 Broker 拉取數據時,也是以批次為單位進行傳遞的。Consumer 從 Broker 拉到一批消息後,客戶端把批次解開,再一條一條交給用戶代碼處理。

Kafka 提供了以下幾個參數來控制消費端的批處理策略:

  • fetch.min.bytes:指定每次拉取請求至少要獲取多少位元組的數據。預設是 1B。
  • fetch.max.bytes:指定每次拉取請求最多能獲取多少位元組的數據。預設是 50MB。
  • fetch.max.wait.ms:指定每次拉取請求最多能等待多長時間。預設是 500ms。
  • max.partition.fetch.bytes:指定每個分區每次拉取請求最多能獲取多少位元組的數據。預設是 1MB。

4. 消息批量壓縮

消息批量壓縮通常與消息批處理一起使用。Kafka 會將多個消息打包成一個批次(Batch),並對批次進行壓縮(例如使用 gzip 或 snappy 演算法),然後再發送給消費者。這樣做的好處是可以節省網路帶寬,提高傳輸效率。

當然,壓縮也有一定的代價,即需要消耗 CPU 資源來進行壓縮和解壓縮。但是對於 Kafka 這樣的高吞吐量的系統來說,網路帶寬往往是更大的瓶頸,所以壓縮是值得的。

Kafka 還提供了一種靈活的壓縮策略,即可以讓生產者、代理和消費者之間協商壓縮格式和級別。生產者可以選擇是否對消息進行壓縮,以及使用哪種壓縮演算法;代理可以選擇是否保留生產者壓縮的消息,或者對其進行重新壓縮;消費者可以選擇是否對收到的消息進行解壓縮。這樣可以根據不同的場景和需求來平衡性能和資源的消耗。

5. 消費者優化

Kafka 的消費者是基於拉模式(pull)的,即消費者主動向伺服器請求數據,而不是伺服器主動推送數據給消費者。這樣做的好處是可以讓消費者自己控制消費的速度和時機,也可以減輕伺服器的負擔,提高整體的吞吐量。

Kafka 的消費者所實現的功能是比較簡潔的,即它們不需要維護太多的狀態和資源,也不需要和伺服器進行複雜的交互。Kafka 的消費者只需要做以下幾件事:

  • 訂閱一個或多個主題(topic),並加入一個消費者組(consumer group)。
    向群組協調器(group coordinator)發送心跳,表明自己還活著,並參與分區再均衡(partition rebalance)。
  • 向分區所在的代理(broker)發送拉取請求(fetch request),獲取消息數據。
  • 提交自己消費到的偏移量(offset),以便在出現故障時恢復消費位置。

可以看到,Kafka 的消費者並不需要保存消息數據,也不需要對消息進行確認或回覆,也不需要處理重試或重覆的問題。這些都由伺服器端來負責。Kafka 的消費者只需要關註如何從伺服器獲取數據,併進行業務處理即可。

6. 未刷新的緩衝寫入

Kafka 在寫入數據時,使用了一種未刷新(flush)的緩衝寫入技術,即它不會立即將數據寫入硬碟,而是先寫入記憶體緩存中,然後由操作系統在適當的時候刷新到硬碟上。這樣做的好處是可以提高寫入速度,減少磁碟 I/O 的開銷。

Kafka 利用了操作系統提供的記憶體映射文件(memory mapped file)功能,將文件映射到記憶體中,使得對文件的讀寫操作就相當於對記憶體的讀寫操作。這樣就避免了用戶空間和內核空間之間的數據拷貝,也避免了系統調用的開銷。

當生產者向 Kafka 發送消息時,Kafka 會將消息追加到記憶體映射文件中,並返回一個確認給生產者。此時消息並沒有真正寫入硬碟,而是由操作系統負責將記憶體中的數據刷新到硬碟上。操作系統會根據一些策略來決定何時刷新數據,例如定期刷新、緩存滿了刷新、系統空閑時刷新等。

當然,這種技術也有一定的風險,即如果操作系統在刷新數據之前發生崩潰或斷電,那麼記憶體中未刷新的數據就會丟失。為瞭解決這個問題,Kafka 提供了一些參數來控制刷新策略,例如:

  • log.flush.interval.messages:指定多少條消息後強制刷新數據。
  • log.flush.interval.ms:指定多少毫秒後強制刷新數據。
  • producer.type:指定生產者是同步還是非同步模式。同步模式下,生產者會等待伺服器刷新數據後再返回確認;非同步模式下,生產者不會等待伺服器刷新數據,而是立即返回確認。

7. GC 優化

Kafka 作為一個 Java 編寫得高性能的分散式消息系統,它需要處理大量的數據讀寫和網路傳輸。這些操作都會涉及到 Java 虛擬機(JVM)的記憶體管理和垃圾回收(GC)機制。如果 GC 不合理或不及時,就會導致 Kafka 的性能下降,甚至出現記憶體溢出或頻繁的停頓。為了幫助使用者優化 GC,Kakfa 有如下建議。

堆記憶體大小

堆記憶體是 JVM 用來存儲對象實例的記憶體區域,它會受到 GC 的管理和回收。堆記憶體的大小會影響 Kafka 的性能和穩定性,如果堆記憶體太小,就會導致頻繁的 GC,影響吞吐量和延遲;如果堆記憶體太大,就會導致 GC 時間過長,影響響應速度和可用性。

通常來說,Kafka 並不需要設置太大的堆記憶體,因為它主要依賴於操作系統的文件緩存(page cache)來緩存和讀寫數據,而不是將數據保存在堆記憶體中。因此 Kafka 建議將堆記憶體大小設置為 4GB 到 6GB 之間。

堆外記憶體大小

堆外記憶體是 JVM 用來存儲非對象實例的記憶體區域,它不會受到 GC 的管理和回收。堆外記憶體主要用於網路 I/O 緩衝區、直接記憶體映射文件、壓縮庫等。

Kafka 在進行網路 I/O 時,會使用堆外記憶體作為緩衝區,以減少數據在用戶空間和內核空間之間的拷貝。同時,Kafka 在進行數據壓縮時,也會使用堆外記憶體作為臨時空間,以減少 CPU 資源的消耗。

因此,堆外記憶體對於 Kafka 的性能也很重要,如果堆外記憶體不足,就會導致緩衝區分配失敗或壓縮失敗,影響吞吐量和延遲。通常來說,Kafka 建議將堆外記憶體大小設置為 8GB 左右。

GC 演算法和參數

GC 演算法是 JVM 用來回收無用對象占用的堆記憶體空間的方法,它會影響 Kafka 的停頓時間和吞吐量。GC 演算法有多種選擇,例如串列 GC、並行 GC、CMS GC、G1 GC 等。

不同的 GC 演算法有不同的優缺點和適用場景,例如串列 GC 適合小型應用和低延遲場景;並行 GC 適合大型應用和高吞吐量場景;CMS GC 適合大型應用和低停頓時間場景;G1 GC 適合大型應用和平衡停頓時間和吞吐量場景等。

通常來說,Kafka 建議使用 G1 GC 作為預設的 GC 演算法,因為它可以在保證較高吞吐量的同時,控制停頓時間在 200ms 以內。同時,Kafka 還建議根據具體情況調整一些 GC 參數,例如:

  • -XX:MaxGCPauseMillis:指定最大停頓時間目標,預設是 200ms。
  • -XX:InitiatingHeapOccupancyPercent:指定觸發併發標記周期的堆占用百分比,預設是 45%。
  • -XX:G1ReservePercent:指定為拷貝存活對象預留的空間百分比,預設是 10%。
  • -XX:G1HeapRegionSize:指定每個堆區域的大小,預設是 2MB。

本文參考

總結

最後感謝大家閱讀,希望本文能對你有所幫助.

關註公眾號【waynblog】每周分享技術乾貨、開源項目、實戰經驗、高效開發工具等,您的關註將是我的更新動力!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • S905L3A(M401A)拆解, 運行EmuELEC和Armbian. S905Lx系列屬於大客戶版本, 對外沒有公開資料, 最早的 S905L/S905LB 是 S905X 的馬甲, 而這個 S905L3A/S905L3AB 則是 S905X2 的馬甲, 因為在性能評測里這兩個U的得分幾乎一樣.... ...
  • 功能 設計一個傳送帶系統,能夠實現傳送帶的開始/停止,正轉/反轉,加減速,對傳送帶的物品計數。 按鈕/app功能控制,oled屏幕/app顯示。 設計框圖 原理圖 軟體構建階段 利用STM32CubeMX生成模板 MCU選型:STM32F103C8T6,雙擊打開。 Ststem Core->SYS: ...
  • # 背景 再很多場景中,我們可能想在子組件中修改父組件的數據,但事實上,vue不推薦我們這麼做,因為數據的修改不容易溯源。 ## Vue2寫法 在vue2中,我們使用`.sync`修飾符+自定義事件`'update:xxx'`,來使父子組件數據同步。 ```html // 父組件 我是父組件,我有{ ...
  • [系列文章目錄和關於我](https://www.cnblogs.com/cuzzz/p/16609728.html) ## 零丶引入 在[Netty源碼學習2——NioEventLoop的執行](https://www.cnblogs.com/cuzzz/p/17641482.html)中,我們學 ...
  • ## 1.1 註釋 **作用**:在代碼中加一些說明和解釋,方便自己或其他程式員程式員閱讀代碼 **兩種格式** 1. **單行註釋**:`// 描述信息` - 通常放在一行代碼的上方,或者一條語句的末尾,==對該行代碼說明== 2. **多行註釋**: `/* 描述信息 */` - 通常放在一段代 ...
  • ## 1 拉取鏡像 指定版本,在git查看相應版本,參考: https://github.com/openzipkin/zipkin 如2.21.7 ```bash docker pull openzipkin/zipkin:2.21.7 ``` ## 2 啟動 Zipkin預設埠為9411。啟動 ...
  • # Nacos集群搭建 # 1.集群結構圖 官方給出的Nacos集群圖: ![image-20210409210621117](https://img2023.cnblogs.com/blog/3014273/202308/3014273-20230827184442168-301140741.pn ...
  • 最近github上發現了一個庫(`plottable`),可以用簡單的方式就設置出花哨的 `DataFrame` 樣式。 github上的地址:[https://github.com/znstrider/plottable](https://github.com/znstrider/plottabl ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...