kafka集羣消息格式之V0版本到V2版本的平滑過渡詳解-kafka 商業環境實戰

版權聲明:本套技術專欄是做者(秦凱新)平時工做的總結和昇華,經過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和集羣環境容量規劃等內容,請持續關注本套博客。版權聲明:禁止轉載,歡迎學習。QQ郵箱地址:1120746959@qq.com,若有任何商業交流,可隨時聯繫。java

1 Kafka 消息格式變遷(滄海桑田)

從0.8.x版本開始到如今的1.1.x版本,Kafka的消息格式也經歷了3個版本。每次版本的改變,都預示着新的優化。那麼Broker做爲Kafka服務載體,承擔了消息協議的響應和接收。緩存

  • 持久化消息。
  • 把消息從發送端過渡到消費端。

2 JVM消息重排機制(Java對象的繁重之軀)

  • Java內存模型保存對象的開銷很大,甚至可能須要花費比消息大兩倍的空間來保存數據。爲了下降這種開銷,JMM(Java Memory Model)會對用戶自定義的類進行字段重排。
  • 垃圾回收隨着堆上數據的擴張,會從總體上拖累應用程序的吞吐量。
  • JMM要求對象必須按照8字節對齊,未對齊的部分會填充空白字符進行補齊padding。

  • 對齊填充計算方法: HotSpot 的對齊方式爲 8 字節對齊,不足的須要 Padding 填充對齊, 公式:架構

    (對象頭 + 實例數據 + padding)% 8 == 0 (0<= padding <8)
    複製代碼
  • 對一個java對象,至少須要16字節對象頭部(對於64位JVM對象一般由8字節的Word組成)。app

3 Kafka 輕裝上陣對象存儲

  • kafka採用Java NIO的ByteBuffer來保存消息,同時依賴文件系統提供的頁緩存機制,再也不依賴java的堆緩存。悖論:寫文件系統時,若是java的堆緩存保存一份對象,那麼頁緩存還會保存一份,何須呢?
  • ByteBuffer是緊湊的二進制字節結構,不須要padding,所以能夠省去不少沒必要要的內存開銷。
  • 在一個64G內存的機器上,kafka可使用內存到58-62GB之間,不用擔憂Java GC 。
  • ByteBuffer能夠節省大量空間,相比於java的堆緩存方案。

4 V0(消息元祖)=> 14字節+12(LOG_OVERHEAD)

  • 版本號: V0版本magic=0,V1版本magic=1,V2版本magic=2學習

  • 屬性:消息壓縮類型。目前僅支持3種壓縮方法。優化

    0X00 未啓動壓縮 0x01 GZIP  0x02 Snappy  0x03 LZ4
    複製代碼
  • 注意key長度字段和value長度字段是固定的,沒有也佔用4個字節,來存 -1編碼

  • 除了key值和value值外,能夠統稱爲是消息頭部信息(header),總共佔用14字節。spa

    假設:存在Key值 爲key , value值爲 value  (一個字符一個字節,共8個字節)
      
      則 header 14 字節 + 值 8字節 = 22字節
      
      當key爲空時,則佔用 19字節
    複製代碼
  • 日誌頭部(LOG_OVERHEAD):每一個Record(v0和v1版)一定對應一個offset和message size。每條消息都一個offset用來標誌它在partition中的偏移量,這個offset是邏輯值,而非實際物理偏移值,message size表示消息的大小,這二者的一塊兒被稱之爲日誌頭部(LOG_OVERHEAD),固定爲12B設計

4.1 V0集合(被V2Batch取代)

總結:一條消息一定包含LOG_OVERHEAD和消息體兩部分。最小佔用12B+14B=26B,在不包含key值和Value值的狀況下。3d

若key =key , value=value 則佔用26(純格式)+8(值空間)=34B

首先建立一個partition數和副本數都爲1的topic,名稱爲「msg_format_v0」,
   而後往msg_format_v0中發送一條key=」key」,value=」value」的消息,以後查看對應的日誌:

    -rw-r--r-- 1 root root       34 Apr 26 02:52 00000000000000000000.log
    
    再次插入一條key=null, value=」value」的消息:
    -rw-r--r-- 1 root root       65 Apr 26 02:56 00000000000000000000.log
複製代碼

總結:發送每一條消息必須攜帶12字節LOG_OVERHEAD,是分散的消息格式設計,沒有體現集合的味道。

5 V1(消息戳進階)=> 22字節+12(LOG_OVERHEAD)

  • kafka從0.10.0版本開始到0.11.0版本以前所使用的消息格式版本爲v1,其比v0版本就多了一個timestamp字段,表示消息的時間戳

  • 所以像v0版本介紹的同樣發送一條key=」key」,value=」value」的消息,那麼此條消息在v1版本中會佔用42B

舉例以下: 發送第一條key=」key」,value=」value」的消息,則佔用22+12+8=42B 發送第二條key=null,value=」value」的消息,,則佔用12+22+5=39B

合在一塊兒發則爲:42+39=81B

5.1 V1集合(被V2Batch取代)

總結:發送每一條消息必須攜帶12字節LOG_OVERHEAD,是分散的消息格式設計,沒有體現集合的味道。

6 V2(變長整型與ZigZag) => 7個字節+ 值key+ 值value =15字節

  • kafka從0.11.0版本開始所使用的消息格式版本爲v2,這個版本的消息相比於v0和v1的版本而言改動很大,同時還參考了Protocol Buffer而引入了變長整型(Varints)和ZigZag編碼。

  • Varints是使用一個或多個字節來序列化整數的一種方法,數值越小,其所佔用的字節數就越少。ZigZag編碼以一種鋸齒形(zig-zags)的方式來回穿梭於正負整數之間,以使得帶符號整數映射爲無符號整數,這樣可使得絕對值較小的負數仍然享有較小的Varints編碼值,好比-1編碼爲1,1編碼爲2,-2編碼爲3。

  • zig-zags 會固定的將每個字節的第一位留做特殊用途,代表該字節是不是最後一個字節,若最高位是1,表示編碼還沒有結束。所以實際上也僅有7位用於實際的編碼,即0-127。另外考慮 -1 ,1, -2, 2 對應 1,2, 3, 4。所以,0-63之間的數字佔1個字節,64-8191之間的數字佔2個字節,8192-1048575之間的數字佔3個字節。kafka broker的配置message.max.bytes的默認大小爲1000012(Varints編碼佔3個字節)。

  • 注意的是Varints並不是一直會省空間,一個int32最長會佔用5個字節(大於默認的4字節),一個int64最長會佔用10字節(大於默認的8字節)

總結 :v2版本的消息格式去掉了crc字段,另外增長了length(消息總長度)、timestamp delta(時間戳增量)、offset delta(位移增量)和headers信息,而且attributes被棄用。

6.1 V2 Record Batch => 61字節+7字節(純格式)+ 值key+ 值value =76字節

v2版本對於消息集(RecordBatch)作了完全的修改,總共佔用了61個字節,好比:把crc校驗放在了Batch這一層,冪等性引入,使用PID標識。epoch引入,標識當前版本。看似增大了消息的容量大小,從大規模消息來算的話,卻帶來了質的飛躍,由於一條純消息格式僅佔用7字節了,而V1佔用22字節,V0佔用14字節。

first offset:表示當前RecordBatch的起始位移。
length:計算partition leader epoch到headers之間的長度。
partition leader epoch:用來確保數據可靠性,詳細能夠參考KIP-101
magic:消息格式的版本號,對於v2版本而言,magic等於2。
attributes:消息屬性,注意這裏佔用了兩個字節。低3位表示壓縮格式,能夠參考v0和v1;第4位表示時間戳類型;第5位表示此RecordBatch是否處於事務中,0表示非事務,1表示事務。第6位表示是不是Control消息,0表示非Control消息,而1表示是Control消息,Control消息用來支持事務功能。
last offset delta:RecordBatch中最後一個Record的offset與first offset的差值。主要被broker用來確認RecordBatch中Records的組裝正確性。
first timestamp:RecordBatch中第一條Record的時間戳。
max timestamp:RecordBatch中最大的時間戳,通常狀況下是指最後一個Record的時間戳,和last offset delta的做用同樣,用來確保消息組裝的正確性。
producer id:用來支持冪等性,詳細能夠參考KIP-98。
producer epoch:和producer id同樣,用來支持冪等性。
first sequence:和producer id、producer epoch同樣,用來支持冪等性。
records count:RecordBatch中Record的個數。
複製代碼

7 昇華

V1 版本的弊端:

  • 空間利用率低,key和value長度都各佔4個字節,浪費。
  • 只保留最新位移,致使若獲取第一條消息,就須要壓縮解壓縮後,遍歷出第一條數據。
  • 每個消息都會有CRC校驗。
  • 沒有消息長度的概念。

V2 新型架構優勢:

  • 增長消息總長度
  • 保留時間戳,同時僅使用1個字節來保存,好比:10條消息,V2須要100個字節。V1就須要800個字節了。 -保存位移增量。
  • 去除CRC校驗。
  • 廢除attribute,移到外層目錄。

總結

本篇技術專欄很是難寫,必須綜合大量資料和實驗才能夠驗證。辛苦成文,各自珍惜。

秦凱新 於深圳

相關文章
相關標籤/搜索