1. 程式人生 > >Kafka叢集磁碟使用率瞬超85%,幕後元凶竟是它?

Kafka叢集磁碟使用率瞬超85%,幕後元凶竟是它?

投稿:新炬網路浙江大資料團隊

Kafka是一種快速、可擴充套件的,設計內在就是分散式的、分割槽的和可複製的提交日誌服務。作為一種高吞吐量的分散式釋出訂閱訊息系統,Kafka被廣泛的應用於海量日誌的收集、儲存。網上有大量Kafka架構、原理介紹的文章,本文不再重複贅述,重點談談Consumer Offset預設儲存機制。

Topic作為一類訊息的邏輯集合,Kafka叢集為其維護了一個分割槽的日誌,其結構如圖:

Kafka叢集

Topic每個分割槽是一個有序的、資訊不斷追加的序列。分割槽中的每個訊息都分配了一個連續的ID號,稱為偏移量(offset),用於唯一標識每個訊息在分割槽中的位置。消費者根據自身儲存的offset值確定各分割槽消費的位置。在0.8版本之前,Kafka一直將consumer的 offset資訊記錄在ZooKeeper中。

ZooKeeper

Kafka的ZooKeeper儲存架構圖

如圖,在offsets的子節點中儲存了不同的topic的offset 資訊。Consumer在消費topic中的資訊時需要不斷的更新ZooKeeper中的offset資訊。

眾所周知,由於ZooKeeper並不適合大批量的頻繁寫入操作,從0.8.2版本開始Kafka開始支援將consumer的位移資訊儲存在Kafka內部的topic中(從0.9.0版本開始預設將offset儲存到系統topic中),雖然此舉解決了ZooKeeper頻繁寫入的效能瓶頸,但卻引入了新的問題。

以下是一個真實的案例:

磁碟使用率異常

某日Kafka叢集的pc-xxx01主機的檔案系統使用率超過80%,觸發告警。通過分析發現,topic __consumer_offset 相關log佔用大量的磁碟空間。

磁碟

圖1

圖2

如圖1、2所示,pc-xxx01主機data3目錄的磁碟使用率超過85%,其中__consumer_offset對應的24號分割槽的日誌佔用了952G,佔總使用量的41%。

__consumer_offset的作用

圖3

如圖3所示,通過消費__consumer_offsets 分割槽24的資料可以發現,該topic儲存的訊息格式為[consumer group,topic name,partition]::[offsetmetadata[offset value,nometadata],committime value,expiratintime value],即一條訊息包含消費組、topic、分割槽、offset值、提交時間、過期時間等資訊。此topic正是kafka用來儲存consumer offset的系統topic(根據實驗驗證該topic的訊息以consumer group為key進行hash,相同consumer group的offset資訊會被插入同一個partition)。

__consumer_offsets資料產生的頻率

Consumer消費訊息之後會向offset manager 傳送offsetCommitrequest請求,offset manager 負責將對應的consumer group、topic、partition、offset等資訊插入__consumer_offsets topic。系統預設每60s為consumer提交一次offsetcommit請求(由auto.commit.interval.ms, auto.commit.enable兩個引數決定)。應用可以採用同步commit的方式進行資料消費(即consumer每處理一條訊息觸發一次commit操作),這可能導致頻繁傳送offsetCommitrequest請求的現象發生。

__consumer_offsets 資料保留策略

資料

圖4

如圖4所示,當前__consumer_offsets 24號分割槽保留了16年10月到現在的所有訊息日誌,總量達到952G。

當前__consumer_offsets 的清理策略為compact,日誌保留週期為24小時,但是系統預設的log.cleaner.enable為false,導致kafka不會對超過保留週期的資料進行壓縮處理,topic保留了系統上線以來的所有歷史資料。

不合理的同步提交方式

通過前期分析發現,__consumer_offsets 資料量暴增的24分割槽的資料主要來自於對log_xxx_plat_xx這個topic的消費組。通過獲取應用相關程式碼分析發現,該topic相關consumer 採用了同步commit方式進行資料消費。

commit

以上是官方文件給出了consumer同步commit消費資訊的兩種示例程式碼。第一種方式,只要消費一條訊息,就會產生一條commit記錄,資料量龐大;第二種方式,對同步commit做了精細化處理,每次批量資料消費,只會對被消費topic各分割槽中最後一條訊息進行commit。如果一個topic包含10個分割槽,每次消費單個分割槽需要處理10條訊息,採用第一種方式將產生100條commit記錄,而第二中方式只會產生10條commit記錄,差距巨大。經開發確認,相關應用正是採用了第一種方式進行同步commit。

系統topic分割槽大小異常的原因

通過以上分析,當前__connsumer_offsets部分分割槽資料量異常的問題是由於以下兩方面原因共同造成:

  1. __connsumer_offsets預設清理策略設定不當,導致過期歷史資料無法正常清理。
  2. 部分應用消費方式不當,導致產生大量commit資訊。

針對該問題,我們後續優化策略如下,取得了不錯的成效。

  1. 要求應用優化程式碼,減少commit資訊的產生,應用進行程式碼改造之後commit資訊日增加量由原先的37G減少到1.5G。
  2. 調整topic 清理策略,將系統log.cleaner.enable設定為true,重起broker節點觸發日誌清理。

優化之後__consumer_offsets 資料量由原先的900G下降到2G。

文章來自微信公眾號:DBAplus社群