點擊上方「中間件興趣圈」,選擇「設爲星標」算法
在雙十一過程當中投入一樣的硬件資源,Kafka 搭建的日誌集羣單個Topic能夠達到幾百萬的TPS,而使用RocketMQ組件的核心業務集羣,集羣TPS只能達到幾十萬TPS,這樣的現象激發了我對二者性能方面的思考。
微信
舒適提示:TPS只是衆多性能指標中的一個,咱們在作技術選型方面要從多方面考慮,本文並不打算就消息中間件選型方面投入太多筆墨,重點想嘗試剖析二者在性能方面的設計思想。網絡
一、文件佈局
1.1 Kafka 文件佈局
Kafka 文件在宏觀上的佈局以下圖所示:
架構
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
文件的組織以 topic + 分區進行組織,每個 topic 能夠建立多個分區,每個分區包含單獨的文件夾,而且是多副本機制,即 topic 的每個分區會有 Leader 與 Follow,而且 Kafka 內部有機制保證 topic 的某一個分區的 Leader 與 follow 不會存在在同一臺機器,而且每一臺 broker 會盡可能均衡的承擔各個分區的 Leader,固然在運行過程當中若是不均衡,能夠執行命令進行手動重平衡。Leader 節點承擔一個分區的讀寫,follow 節點只負責數據備份。併發
Kafka 的負載均衡主要依靠分區 Leader 節點的分佈狀況。負載均衡
分區的 Leader 節點負責讀寫,而從節點負責數據同步,若是Leader分區所在的Broker節點發生宕機,會觸發主從節點的切換,會在剩下的 follow 節點中選舉一個新的 Leader 節點,其數據的流入流程以下圖所示:
運維
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
ack = 0異步
不等broker端確認就直接返回,即客戶端將消息發送到網絡中就返回發送成功。分佈式
ack = 1
Leader 節點接受並存儲後向客戶端返回成功。
ack = -1
Leader節點和全部的Follow節點接受併成功存儲再向客戶端返回成功。
1.2 RocketMQ 文件佈局
RocketMQ 的文件佈局以下圖所示:
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
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,其代碼截圖以下:
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
2.2 RocketMQ 消息寫入方式
RocketMQ 的消息寫入支持 內存映射 與 FileChannel 寫入兩種方式, 示例以下圖所示:
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
2.3 消息寫入方式對比
儘管 RocketMQ 與 Kafka 都支持 FileChannel 方式寫入,但 RocketMQ 基於 FileChannel 寫入時調用的 API 卻並非 transferTo,而是先調用 writer,而後定時 flush 刷寫到磁盤,其代碼截圖以下:
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
爲何 RocketMQ 不調用 transerTo 方法呢,我的以爲和 RocketMQ 須要在 Broker 組裝 MQ 消息格式有關,須要從網絡中解碼請求,傳輸到堆內存,而後對消息進行加工,最終持久化到磁盤相關。
從網上查詢資料中大概傾向於這樣一個 觀點:sendfile 系統調用相比內存映射多了一次從用戶緩存區拷貝到內核緩存區,但對於超過64K的內存寫入時每每 sendfile 的性能更高,多是因爲 sendfile 是基於塊內存的。
三、消息發送方式
3.1 Kafka 消息發送機制
Kafka 在消息發送客戶端採用了一個雙端隊列,引入了批處理思想,其消息發送機制以下圖所示:
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
爲了提升 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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。