https://github.com/apache/kafka/pull/17342
背景故事
昨天的抒情廢文沒有半點技術內涵,我深刻反省。所以今天這篇回歸正題,來談一個跟Kafka
使用者非常非常有關的題目!
大家有沒有用過Consumer
的群組機制?如果沒有的話這裡很快介紹一下,Group
機制目的是降低使用者在大量部署Consumer
的痛苦,最有名的痛苦有兩個,首先是Consumer
大量部署時要如何去分配任務、第二個就是Consumer
開開關關後如何延續之前的進度?
針對第一個痛苦,Group
機制會自動將任務分配給屬於同一個Group
下的Consumers
們,例如總共有partition_0
和partition_1
兩個資料區段需要處理,此時Group
內總共有兩個Consumer
的話,那麼此機制就會讓兩個Consumer
各自負責一個partition
,和樂融融大家都有事情做。所以使用者可以很放心的在Group
內加入更多Consumer
,不用擔心會不會有人沒事做有人做太多,Group
機制會努力的把事情分配好不讓人當薪水小偷。
那麼第二個痛苦呢?大量Consumer
總是會有開開關關重開機升級的時刻,沒有人喜歡重複做同樣的工作、當然也沒人想要讀取重複的資料,Group
機制自然體貼的會幫忙把各個partition
的讀取紀錄保存下來,當consumer
重啟後要來繼續拉取partition
資料時,Group
機制會先從伺服器端把上次的讀取進度找回來,然後Consumer
就可以著讀取,就像是我們在串流電影一樣,電視看完移動到床上用平板接著看順暢舒服。
接著拉回今天的主題,Consumer
實際上是如何找到上次的讀取紀錄呢?這裏給兩個關鍵字:OffsetFetchRequest
、ListOffsetsRequest
,是不是看到名字就立刻聯想到做法了?沒錯,小編這就來把各位讀者腦袋裡的想法描繪出來。
首先,Consumer
會先送出OffsetFetchRequest
來查詢上次的讀取進度,這句敲完大家是不是覺得那不就完事了嘛?怎麼還會需要ListOffsetsRequest
?這是為了處理一個情境,這個情境叫做這個partition
上完全沒有畫面紀錄,沒錯嘛,可能這是一個新的partition
又或是上一個傢伙當薪水小偷都沒辦事,那這時候該怎麼辦?自然就是ListOffsetsRequest
該出場了,Consumer
會根據使用者的參數設定說當沒有記錄時要從哪裡開始讀取,可以從頭或是從最新等等,然後就會使用ListOffsetsRequest
來把對應的紀錄拿回來,接著Consumer
就可以開始上工了!
聽起來一切很美好吧?但是上述的流程其實可能會有一個問題,這個問題就是上述的流程其實需要與伺服器端至少來回兩次對話,如果在對話過程中要處理的partitions
有變化該怎麼辦?舉個例子,一開始送OffsetFetchRequest
的時候要查partition_0
和partition_1
,然後等到ListOffsetsRequest
要上場時這個Consumer
要處理的partition
突然多了一個partition_2
那該怎麼辦?此時的partition_2
一定沒有上次的讀取紀錄,難道我們就把它當成沒有記錄嘛?當然不行,這樣很可能會出現掉資料或是重複讀取的尷尬狀況 ...
解決辦法
既然知道問題的根源,那解決辦法其實也很簡單,那就是雖然不忍心但只好讓partition_2
留到下次輪詢時再來處理,也就是說ListOffsetsRequest
要處理的對象只會限定於OffsetFetchRequest
處理過的partition
,如果是在過程中突然加入的partition
就會自動被排除在外,如此就可以避免Consumer
設定不正確的讀取紀錄!
廣告
歡迎訂閱全臺最鬆散的開源社群源來適你,上面不定期會有各種開源的廢文。也歡迎參加全臺最鬆散的開源討論頻道,上面有一群網友一起在刷開源技術