Kafka 和 RocketMQ 之性能對比

點擊上方「中間件興趣圈」選擇「設爲星標」算法

作積極的人,越努力越幸運!緩存

在雙十一過程當中投入一樣的硬件資源,Kafka 搭建的日誌集羣單個Topic能夠達到幾百萬的TPS,而使用RocketMQ組件的核心業務集羣,集羣TPS只能達到幾十萬TPS,這樣的現象激發了我對二者性能方面的思考。
微信

舒適提示:TPS只是衆多性能指標中的一個,咱們在作技術選型方面要從多方面考慮,本文並不打算就消息中間件選型方面投入太多筆墨,重點想嘗試剖析二者在性能方面的設計思想。網絡

一、文件佈局


1.1 Kafka 文件佈局

Kafka 文件在宏觀上的佈局以下圖所示:
架構

正如上圖所示,Kafka 文件佈局的主要特徵以下:

文件的組織以 topic + 分區進行組織,每個 topic 能夠建立多個分區,每個分區包含單獨的文件夾,而且是多副本機制,即 topic 的每個分區會有 Leader 與 Follow,而且 Kafka 內部有機制保證 topic 的某一個分區的 Leader 與 follow 不會存在在同一臺機器,而且每一臺 broker 會盡可能均衡的承擔各個分區的 Leader,固然在運行過程當中若是不均衡,能夠執行命令進行手動重平衡。Leader 節點承擔一個分區的讀寫,follow 節點只負責數據備份。併發

Kafka 的負載均衡主要依靠分區 Leader 節點的分佈狀況。負載均衡

分區的 Leader 節點負責讀寫,而從節點負責數據同步,若是Leader分區所在的Broker節點發生宕機,會觸發主從節點的切換,會在剩下的 follow 節點中選舉一個新的 Leader 節點,其數據的流入流程以下圖所示:
運維

分區 Leader 收到客戶端的消息發送請求時,是寫入到 Leader 節點後就返回仍是要等到它的從節點所有寫入後再返回,這裏很是關鍵,會直接影響消息發送端的時延,故 Kafka 提供了 ack 這個參數來進行策略選擇:
  • ack = 0異步

    不等broker端確認就直接返回,即客戶端將消息發送到網絡中就返回發送成功。分佈式

  • ack = 1

    Leader 節點接受並存儲後向客戶端返回成功。

  • ack = -1
    Leader節點和全部的Follow節點接受併成功存儲再向客戶端返回成功。

1.2 RocketMQ 文件佈局

RocketMQ 的文件佈局以下圖所示:

RocketMQ 全部主題的消息都會寫入到 commitlog 文件中,而後基於 commitlog 文件構建消息消費隊列文件(Consumequeue),消息消費隊列的組織結構按照 /topic/{queue} 進行組織。 從集羣的視角來看以下圖所示:
RocketMQ 默認採起的是主從同步,固然從RocketMQ4.5引入了多副本機制,但其 副本的粒度爲 Commitlog 文件 ,上圖中不一樣 master 節點之間的數據完成不同(數據分片),而主從節點節點數據一致。

1.3 文件佈局對比

Kafka 中文件的佈局是以 Topic/partition ,每個分區一個物理文件夾,在分區文件級別實現文件順序寫,若是一個Kafka集羣中擁有成百上千個主題,每個主題擁有上百個分區,消息在高併發寫入時,其IO操做就會顯得零散,其操做至關於隨機IO,即 Kafka 在消息寫入時的IO性能會隨着 topic 、分區數量的增加,其寫入性能會先上升,而後降低

而 RocketMQ在消息寫入時追求極致的順序寫,全部的消息不分主題一概順序寫入 commitlog 文件,並不會隨着 topic 和 分區數量的增長而影響其順序性。但經過筆者的實踐來看一臺物理機並使用SSD盤,但一個文件沒法充分利用磁盤IO的性能。

二者文件組織方式,除了在磁盤的順序寫方面有所區別後,因爲其粒度的問題,Kafka 的 topic 擴容分區會涉及分區在各個 Broker 的移動,其擴容操做比較重,而 RocketMQ 數據存儲是基於 commitlog 文件的,擴容時不會產生數據移動,只會對新的數據產生影響,RocketMQ 的運維成本對 Kafka 更低。

最後 Kafka 的 ack 參數能夠類比 RocketMQ 的同步複製、異步複製。

Kafka 的 ack 參數爲 1 時,對比 RocketMQ 的異步複製;-1 對標 RocketMQ 的 同步複製,而 -1 則對標 RocketMQ 消息發送方式的 oneway 模式。

二、數據寫入方式


2.1 Kafka 消息寫入方式

Kafka 的消息寫入使用的是 FileChannel,其代碼截圖以下:


而且在消息寫入時使用了 transferTo 方法,根據網上的資料說 NIO 中網絡讀寫真正是零拷貝的就是須要調用 FileChannel 的 transferTo或者 transferFrom 方法,其內部機制是利用了 sendfile 系統調用。

2.2 RocketMQ 消息寫入方式

RocketMQ 的消息寫入支持 內存映射 與 FileChannel 寫入兩種方式, 示例以下圖所示:

2.3 消息寫入方式對比

儘管 RocketMQ 與 Kafka 都支持 FileChannel 方式寫入,但 RocketMQ 基於 FileChannel 寫入時調用的 API 卻並非 transferTo,而是先調用 writer,而後定時 flush 刷寫到磁盤,其代碼截圖以下:


爲何 RocketMQ 不調用 transerTo 方法呢,我的以爲和 RocketMQ 須要在 Broker 組裝 MQ 消息格式有關,須要從網絡中解碼請求,傳輸到堆內存,而後對消息進行加工,最終持久化到磁盤相關。

從網上查詢資料中大概傾向於這樣一個 觀點:sendfile 系統調用相比內存映射多了一次從用戶緩存區拷貝到內核緩存區,但對於超過64K的內存寫入時每每 sendfile 的性能更高,多是因爲 sendfile 是基於塊內存的。

三、消息發送方式


3.1 Kafka 消息發送機制

Kafka 在消息發送客戶端採用了一個雙端隊列,引入了批處理思想,其消息發送機制以下圖所示:

客戶端經過調用 kafka 的消息發送者發送消息時,消息會首先存入到一個雙端隊列中,雙端隊列中單個元素爲 ProducerBatch,表示一個發送批次,其最大大小受參數 batch.size 控制,默認爲 16K。 而後會單獨開一個 Send 線程,從雙端隊列中獲取一個發送批次,將消息按批發送到 Kafka集羣中,這裏引入了 linger.ms 參數來控制 Send 線程的發送行爲。

爲了提升 kafka 消息發送的高吞吐量,即控制在緩存區中未積滿 batch.size 時來控制消息發送線程的行爲,是當即發送仍是等待必定時間,若是linger.ms 設置爲 0表示當即發送,若是設置爲大於0,則消息發送線程會等待這個值後纔會向broker發送。linger.ms 參數者會增長響應時間,但有利於增長吞吐量。有點相似於 TCP 領域的 Nagle 算法

Kafka 的消息發送,在寫入 ProducerBatch 時會按照消息存儲協議組織好數據,在服務端能夠直接寫入到文件中。

3.2 RocketMQ 消息發送機制

RocketMQ 消息發送在客戶端主要是根據路由選擇算法選擇一個隊列,而後將消息發送到服務端,消息會在服務端按照消息的存儲格式進行組織,而後進行持久化等操做。

3.3 消息發送對比

Kafka 在消息發送方面比 RokcetMQ 有一個顯著的優點就是消息格式的組織是發生在客戶端,這樣會有一個大的優點節約了 Broker 端的CPU壓力,客戶端「分佈式」的承接了其優點,其架構方式有點相似 shardingjdbc 與 MyCat 的區別。

Kafka 在消息發送端另一個特色是引入了雙端緩存隊列,Kafka 無處不在追求批處理,這樣顯著的特色是能提升消息發送的吞吐量,但與之帶來的是增大消息的響應時間,而且帶來了消息丟失的可能性,由於 Kafka 追加到消息緩存後會返回成功,若是消息發送方異常退出,會帶來消息丟失。

Kafka 中的 linger.ms = 0 可類比 RocketMQ 消息發送的效果。

但 Kafka 經過提供 batch.size 與 linger.ms 兩個參數按照場景進行定製化,比 RocketMQ 靈活。

例如日誌集羣,一般會調大 batch.size 與 linger.ms 參數,重複發揮消息批量發送機制,提升其吞吐量;但若是對一些響應時間比較敏感的話,能夠適當減小 linger.ms 的值。

四、總結


從上面的對比來看,Kafka 在性能上綜合表現確實要比 RocketMQ 更加的優秀,但在消息選型過程當中,咱們不只僅要參考其性能,還有從功能性上來考慮,例如 RocketMQ 提供了豐富的消息檢索功能、事務消息、消息消費重試、定時消息等。

筆者我的認爲一般在大數據、流式處理場景基本選用 Kafka,業務處理相關選擇 RocketMQ。

歡迎加入個人知識星球,一塊兒交流源碼,探討架構,揭祕億級訂單的架構設計與實踐經驗,打造高質量的技術交流圈,爲廣大星友提供高質量問答服務,長按以下二維碼加入。


本文分享自微信公衆號 - 中間件興趣圈(dingwpmz_zjj)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索