https://issues.apache.org/jira/browse/KAFKA-17552
背景故事
LIST_OFFSETS
是一個非常好用的請求,在之前的鐵人賽文章已經講述過有哪些用法,所以歡迎大家去閱讀一下補充背景知識。
一秒
兩秒
三秒
好的,感謝大家辛苦閱讀背景知識,既然大家都已經有背景知識了,那我們就快速進入今天的主題,到底LIST_OFFSETS
這個請求在 remote storage
下會有甚麼問題呢?這個問題其實來自kafka
的資料是允許使用者自己定義timestamp
,使用者如果比較有創意是可以在新的資料塞一個很舊的timestamp
,這個彈性也導致LIST_OFFSETS
在搜尋MAX_TIMESTAMP
的時候變得很複雜 ...
這個複雜有多複雜?複雜來自於有MAX_TIMESTAMP
的資料可能落在任何一個地方,然後又很不幸的是Kafka
並沒有一個索引去追蹤目前MAX_TIMESTAMP
的位置,換言之,LIST_OFFSETS
在處理MAX_TIMESTAMP
時都必須依照此時此刻的資料集去做搜尋,講到這裏,大家心理一定跑出一個疑問...「欸靠,這個成本很高吧?」
沒錯,相較於其他有做索引的請求,MAX_TIMESTAMP
是一個相對慢的操作,但是大家也不要太擔心真的要去查詢每一筆資料,事實上kafka
也很害怕這個操作把系統搞爆,所以就算我們還是有針對batch
這個等級來做MAX_TIMESTAMP
的索引,所以實際上在執行MAX_TIMESTAMP
的查詢時還是可以稍微加速一下:
timestamp
的 segment
segment
查找有最大timestamp
的batch
batch
查找有最大timestamp
的record
上述流程雖然很大程度避免搜尋每一筆資料,但是熟悉演算法的工程師一定馬上發現問題,「欸?這樣三次搜尋的時間還是跟資料量成正比阿」沒錯,這就是爲何前面文章說這個LIST_OFFSETS
操作是一個相對慢的操作,那麼爲何我們會有這個狀況?這個故事就要追朔到KAFKA-16310 ...
如果我們要在記憶體內追蹤MAX_TIMESTAMP
,那該怎麼做?自然就是要在資料進來的時候找出有最大timestamp
的資料,也就是我們必須要輪詢進來的每一筆資料,但輪詢每一筆資料本身就是一個成本,試想看看如果這批資料是已經壓縮過了,那麼輪詢的過程就必須要解壓縮,這就會產生很大的開銷。因此在kafka
各種進資料的路徑上,真的會去輪詢的路徑其實不多,那麼我們要為了某一個請求而產生這可能很高的開銷嘛?自然是大可不必。所以在 KAFKA-16310一陣激烈的討論後,我們決定利大於弊的犧牲MAX_TIMESTAMP
這個操作,進而避免讓每個進資料的路徑付出昂貴的成本
本來以為這個美好的一天已經順利度過,但我們忽略了一個很重要的新功能,也就是remote storage
的存在,也就是有些資料會放在remote storage
上面,上述的查找過程完全忽略了remote storage
,也就是說目前的實作只是在部分資料中查找可能有最大timestamp
....
解決辦法
既然知道問題了,那麼故事也很簡單同時也很殘酷,remote storage
一樣沒有針對最大timestamp
建立索引,所以目前唯一且唯一的解法,自然就是我們也要在remote storage
中翻出有最大timestamp
的資料:
timestamp
的 segment
remote storage
查找有最大 timestamp
的 segment
segment
查找有最大timestamp
的segment
segment
查找有最大timestamp
的batch
batch
查找有最大timestamp
的record
以上就是本期的故事,如果你覺得這個解法太不優雅讓你看得渾身不舒服,歡迎來社群提供你的建議,我們kafka
永遠歡迎夠酷的想法!
廣告
歡迎訂閱全臺最鬆散的開源社群源來適你,上面不定期會有各種開源的廢文。也歡迎參加全臺最鬆散的開源討論頻道,上面有一群網友一起在刷開源技術