kafka之消息格式

Kafka版本

  1. kafka版本1.1.1,可能絕大部分也適用於kafka 0.10.x及以上版本。

消息格式

  1. 目前Kafka消息格式有三個版本,V0、V1和V2。

V0版本

  1. V0版本主要是指Kafka0.10.0.0之前的版本,是kafka最早的消息版本

    image-20191007223724347

  2. 字段含義

    • CRC(4B):CRC校驗碼,佔用4個字節,校驗magic至value之間字節是否被篡改
    • magic(1B):消息格式版本號,佔用1個字節。V0版本是0,V1版本是1,V2版本是2
    • attributes(1B):屬性字段,佔用1個字節,只使用低3位表示消息的壓縮類型,其他5位是保留位。
      • 0表示NONE,表示不啓用壓縮
      • 1表示GZIP
      • 2表示SNAPPY
      • 3表示LZ4
    • key length(4B):表示消息的key的長度。如果爲-1,則表示沒有設置key,即key=null
    • key:消息key,長度由key length值指定。如果key length值是-1,則無key(沒有此字段)
    • value length(4B):表示消息的長度,佔用4字節。
    • value:消息value,長度由value length值指定。如果value length值是-1,則無value,消息沒有該字段。
  3. 消息頭部(message Header):除了Key和Value之外的所有字段統稱爲消息頭部。總共佔用14字節(4B+1B+1B+4B+4B),即V0版本的消息長度最小是14B

  4. 此版本的問題

    • 即使不指定key(即key length=-1),還是要佔用4個字節的空間
    • 即使不指定value(即value length=-1),還是要佔用4個字節的空間
    • 沒有消息的時間信息。kafka定期刪除過期log只能依靠文件的最後修改時間。文件系統最後的修改時間很容易受到外部不確定因素的干擾。

V1版本

  1. V1版本主要是[0.10.0.0,0.11.0.0)之間的版本

    image-20191007225031775

  2. V1與V0的主要差異

    • 引入了8B的時間戳,即V1版本的消息頭部最小是22B(14B+8B)
    • 屬性字段第4位被用於指定時間戳類型
      • 0表示timestamp類型爲CREATE_TIMECREATE_TIME表示在消息創建時由producer指定的時間戳
      • 1表示timestamp類型爲LOG_APPEND_TIMELOG_APPEND_TIME 表示消息被髮送到broker端時由broker指定的時間戳。

Message Set

  1. Kafka的消息層次分爲:消息集合(message set)和消息。V0和V1版本使用的是日誌項(log entry),以下是日誌項的格式

    image-20191011222435227

  2. 每個消息集合中的日誌項由shallow message和log entry header組成

    • shallow message:如果沒有啓用消息壓縮,那麼shallow message就是這條消息本身。如果啓用消息壓縮,kafka會將多條消息壓縮到一起統一封裝成shallow message的value字段。此時該shallow message被稱爲wrapper消息(或者外部消息),而value字段中包含的消息則被稱爲inner消息(內部消息)。v0和v1版本中的日誌項只能包含一條shallow message
    • log entry header(日誌項頭部):由8B的offset和4B的size組成。offset指該消息在分區日誌中的offset,如果是未壓縮的消息,該offset就是消息的offset,否則該字段表示wrapper消息中最後一條inner消息的offset。因此,從V0、V1版本消息集合日誌項中搜索該日誌項的起始偏移是非常困難的,需要遍歷所有的inner消息,即broker需要解壓縮操作。

V0與V1的缺陷

  1. 空間利用率不高:不論key和value長度是多少,總是固定佔用4B
  2. 只保存最新消息偏移量:如果啓用壓縮,offset是消息集合中最後一條消息的offset。如果想要獲取第1條消息的offset,必須解壓所有消息並加載到內存中,然後反向遍歷才能獲取到
  3. CRC校驗,爲每條消息都執行CRC沒有必要
  4. 未保存消息長度:每次需要單條消息的總字節數信息時都需要計算得出,沒有使用單獨字段來保存。每次計算時爲了避免對現有數據結構的破壞,都需要大量的對象副本, 解序列化效率很低。

V2版本

  1. V1版本主要是0.11.0.0(包含)之後的版本。此版本相比於v0和v1改動很大,引入了變長整型(Varints)和ZigZag編碼(借鑑ProtoBuffer中的Zig-zag編碼方式,絕對值較小的整數佔用比較少的字節)。Varints是使用一個或多個字節來序列化整數的一種方法,數值越小,其所佔用的字節數就越少。Zig-zag編碼方式,使得絕對值較小的整數佔用比較少的字節

    image-20191007235412739

  2. 字段詳解

    • 增加消息總長度字段
    • 可變時間戳,使用一個可變長度保存與batch起始時間戳的差值。差值一般很小,所以需要保存的字節也小
    • 增加offset,保存消息offset與外層batch起始offset的差值,節省消息總字節數
    • 增加消息headers,主要是爲了滿足用戶定製化需求,用戶手動設置的
    • 去除CRC校驗,V2不再爲每條消息計算CRC32值,而是對整個消息batch進行CRC校驗
    • 廢棄attribute字段。V2版本將原先保存在attribute字段中的壓縮類型、時間戳等信息統一保存在外層batch格式字段中,但是依然保留了單字節attribute爲了以後擴展使用。
  3. V2版本中消息集合(message set)被消息批次所取代,叫做RecordBatch。這裏的RecordBatch與producer中的batch不是一個含義。

    image-20191011231740980

  4. bath字段詳解

    • CRC被放入Batch

    • 增加2B的attribute。

      • 最低3位依然是壓縮類型

      • 第4位保存時間戳類型(NO_TIMESTAMP_TYPE是-1,CREATE_TIME是0,LOG_APPEND_TIME是1)。

      • 第5位事務類型(事務消息是1,非事務消息是0)

      • 第6位控制類型(ABORT是0,COMMIT是1,UNKNOWN是-1)

    • PID、 producer epoch 和序列號等信息都是 0.11.0.0 版本爲了實現冪等性 producer 和支持事務而引入的。Kafka依靠PID+epoch來辨別消息是否己成功提交,從而防止出現重複生產消息。

  5. 0.11.0.0版本(及以後)的 Kafka消息在支持事務、幕等性 producer的同時還在一定程度上減少了網絡I/O和磁盤 I/O 的開銷(因V2版本協議的緣故)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章