9. Kafka 消息壓縮與日誌壓縮
9.1 消息壓縮
日誌 v2 版本的壓縮,優化內容:
- RecordBatch 與 Record:對多條消息 (Record) 進行壓縮,稱爲消息集 (RecordBatch),壓縮形式爲外層 (RecordBatch) - 內層消息 (Record) 的形式,每個消息集對應一個或多個消息;
- 變長字段 Variant:變長字段用來對數值內容進行壓縮;
- (1) Variant 變長字段可以表示 int32, int64, enum 等多種類型的數據;
- (2) Variant 使用 Zigzag 編碼,對小數值優化效果很好,尤其是小數值的負數;
- 例如 int32 類型的 1, -1 佔用 4Bytes,而用 Variant 編碼後只佔用 1Bytes;
- 內層消息的偏移量、時間戳字段使用增量表示,這樣內層多條 Record 的偏移量與時間戳數值很小,用 Variant 編碼的壓縮效果明顯;
9.2 日誌壓縮
Kafka 日誌壓縮類似於 Redis 持久化的 RDB 模式,假設 Kafka 崩潰,通過日誌文件恢復最終狀態時,Kafka 只需要關心最新狀態,並不關心每一時刻的狀態。
Kafka 日誌壓縮主要是針對兩種數據:
- Key 值相同的數據,壓縮後只記錄同 Key 值最新的一條數據;
- Key 不爲空,Value 爲空的消息,這種消息在日誌壓縮過程中會被設置爲墓碑消息;
9.2.1 日誌壓縮結構
日誌壓縮是對分區進行的。在 Kafka 的 log.dirs
路徑下有文件 cleaner-offset-checkpoint
文件,該文件中包含所有分區已清理數據偏移量信息。
對於每個分區的日誌分段,可以將其分成兩個部分:
- clean:被清理的部分,所以它的消息偏移量是斷續的;
- dirty:沒有被清理的部分,該部分的消息偏移量連續的;
9.2.2 日誌壓縮流程
- 日誌清理線程定時執行壓縮任務,遍歷分區內所有消息,記錄所有 key 值,以及每個 Key 值最後出現的 offset,將兩者關聯並記錄下來,形成一個 key(hashcode) - offset 的 Map(極小可能會出現 Hash 碰撞情況);
- 清理過程中,同時會標記墓碑消息,在後續週期的日誌清理過程中,將墓碑消息清除;
- 每次清理對日誌分段分組,以大小之和不超過 1G 的日誌文件,或者大小之和不超過 10M 的索引文件爲一組,進行壓縮處理;
- 壓縮處理完畢後,替代原有日誌文件,並將日誌壓縮結果存到
log.dirs/cleaner-offset-checkpoint
文件中。