面試官:你對Kafka比較熟? 那說說kafka日誌段如何讀寫的吧?

△Hollis, 一個對Coding有着獨特追求的人△

這是Hollis的第 289 篇原創分享

作者 l Yes

來源 l Hollis(ID:hollischuang)

引子

之所以寫這篇文章是因爲之前面試時候被面試官問到(倒)了,面試官說:“你說你對Kafka比較熟?看過源碼? 那說說kafka日誌段如何讀寫的吧?”

我心裏默默的說了句 “擦…我說看過一點點源碼,不是億點點。早知道不提這句了!”,那怎麼辦呢,只能回家等通知了啊。

但是爲了以後找回場子,咱也不能坐以待斃,日拱一卒從一點點到億點點。今天我們就來看看源碼層面來Kafka日誌段的是如何讀寫的。

Kafka的存儲結構

總所周知,Kafka的Topic可以有多個分區,分區其實就是最小的讀取和存儲結構,即Consumer看似訂閱的是Topic,實則是從Topic下的某個分區獲得消息,Producer也是發送消息也是如此。

topic-partition關係

上圖是總體邏輯上的關係,映射到實際代碼中在磁盤上的關係則是如下圖所示:

每個分區對應一個Log對象,在磁盤中就是一個子目錄,子目錄下面會有多組日誌段即多Log Segment,每組日誌段包含:消息日誌文件(以log結尾)、位移索引文件(以index結尾)、時間戳索引文件(以timeindex結尾)。其實還有其它後綴的文件,例如.txnindex、.deleted等等。篇幅有限,暫不提起。

以下爲日誌的定義

以下爲日誌段的定義

indexIntervalBytes可以理解爲插了多少消息之後再建一個索引,由此可以看出Kafka的索引其實是稀疏索引,這樣可以避免索引文件佔用過多的內存,從而可以在內存中保存更多的索引。對應的就是Broker 端參數log.index.interval.bytes 值,默認4KB。

實際的通過索引查找消息過程是先通過offset找到索引所在的文件,然後通過二分法找到離目標最近的索引,再順序遍歷消息文件找到目標文件。這波操作時間複雜度爲O(log2n)+O(m),n是索引文件裏索引的個數,m爲稀疏程度。

這就是空間和時間的互換,又經過數據結構與算法的平衡,妙啊!

再說下rollJitterMs,這其實是個擾動值,對應的參數是log.roll.jitter.ms,這其實就要說到日誌段的切分了,log.segment.bytes,這個參數控制着日誌段文件的大小,默認是1G,即當文件存儲超過1G之後就新起一個文件寫入。這是以大小爲維度的,還有一個參數是log.segment.ms,以時間爲維度切分。

那配置了這個參數之後如果有很多很多分區,然後因爲這個參數是全局的,因此同一時刻需要做很多文件的切分,這磁盤IO就頂不住了啊,因此需要設置個rollJitterMs,來岔開它們。

怎麼樣有沒有聯想到redis緩存的過期時間?過期時間加個隨機數,防止同一時刻大量緩存過期導致緩存擊穿數據庫。看看知識都是通的啊!

日誌段的寫入

1、判斷下當前日誌段是否爲空,空的話記錄下時間,來作爲之後日誌段的切分依據

2、確保位移值合法,最終調用的是AbstractIndex.toRelative(..)方法,即使判斷offset是否小於0,是否大於int最大值。

3、append消息,實際上就是通過FileChannel將消息寫入,當然只是寫入內存中及頁緩存,是否刷盤看配置。

4、更新日誌段最大時間戳和最大時間戳對應的位移值。這個時間戳其實用來作爲定期刪除日誌的依據

5、更新索引項,如果需要的話(bytesSinceLastIndexEntry > indexIntervalBytes)

最後再來個流程圖

消息寫入流程

日誌段的讀取

1、根據第一條消息的offset,通過OffsetIndex找到對應的消息所在的物理位置和大小。

2、獲取LogOffsetMetadata,元數據包含消息的offset、消息所在segment的起始offset和物理位置

3、判斷minOneMessage是否爲true,若是則調整爲必定返回一條消息大小,其實就是在單條消息大於maxSize的情況下得以返回,防止消費者餓死

4、再計算最大的fetchSize,即(最大物理位移-此消息起始物理位移)和adjustedMaxSize的最小值(這波我不是很懂,因爲以上一波操作adjustedMaxSize已經最小爲一條消息的大小了)

5、調用 FileRecordsslice 方法從指定位置讀取指定大小的消息集合,並且構造FetchDataInfo返回

再來個流程圖:

消息讀取流程

小結

從哪裏跌倒就從哪裏爬起來對吧,這波操作下來咱也不怕下次遇到面試官問了。

區區源碼不過爾爾,哈哈哈哈(首先得要有氣勢)

實際上這只是Kafka源碼的冰山一角,長路漫漫。雖說Kafka Broker都是由Scala寫的,不過語言不是問題,這不看下來也沒什麼難點,註釋也很豐富。遇到不知道的語法小查一下搞定。

所以強烈建議大家入手源碼,從源碼上理解。今天說的 appendread 是很核心的功能,但一看也並不複雜,所以不要被源碼這兩個字嚇到了。

看源碼可以讓我們深入的理解內部的設計原理,精進我們的代碼功力(經常看着看着,我擦還能這麼寫)。當然還有系統架構能力。

然後對我而言最重要的是可以裝逼了(哈哈哈)。

情景劇

老白正目不轉睛盯着監控大屏,“爲什麼?爲什麼Kafka Broker物理磁盤 I/O 負載突然這麼高?”。寥寥無幾的秀髮矗立在老白的頭上,顯得如此的無助。

“是不是設置了 log.segment.ms參數 ?試試 log.roll.jitter.ms吧”,老白擡頭間我已走出了辦公室,留下了一個偉岸的背影和一顆鋥亮的光頭!

“我變禿了,也變強了”



往期推薦

人人網慘遭全網下架,但是我並不同情他!

漫話:爲什麼程序員喜歡使用0 ≤ i < 10這種左閉右開的形式寫for循環?

什麼是 “馬太效應” ?

本文由“壹伴編輯器”提供技術支

 

直面Java第329期:哪個命令可以監控虛擬機各種運行狀態信息?

深入併發第013期:拓展synchronized——鎖優化

如果你喜歡本文,

請長按二維碼,關注 Hollis.

轉發至朋友圈,是對我最大的支持。

點個 在看 

喜歡是一種感覺

在看是一種支持

↘↘↘

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