在這篇文章中,我將從訊息在kafka中的物理儲存方式講起,介紹分割槽-日誌段-日誌的各個層次。
根據消費者的消費可能引發的問題,我將介紹kafka中的位移主題,以及消費者要怎麼提交位移到這個位移主題中。
最後,我將聊一聊消費者rebalance的原因,以及不足之處。
我們那個時候所表達的意思是,訊息的生產跟消費是處於topic中的partition這個維度的,而不是位於主題的維度。
也就是說,我們那個時候對kafka的理解,是處在topic下的每個parititon,都有乙個稱為「佇列」的資料結構,所有送往這個主題的訊息,會被分配到其中的乙個parititon中。
這樣的設計可以避免訊息佇列的效能在io上具有瓶頸。
在這一節中,我們將進一步的解釋kafka的訊息儲存方式。
我們所理解的「訊息」,在kafka中被稱為日誌。
在每乙個broker中,儲存了多個名字為-
的資料夾,例如test-1
、test-2
。
這裡的意思是,這個broker中能夠處理topic為test,分割槽為1和2的訊息。
但是注意,對於「parititon」這個名詞來說,他也是乙個邏輯上的概念,對應在broker中只是乙個資料夾,那麼什麼才是物理意義上的概念呢,我們接著往下看。
在-
的資料夾內部,包含了很多很多的檔案,裡面的檔名都是64位的長整數。
例如:
在這張圖中,乙個分割槽,包含了多個log segment
。注意,這裡的log segment
也是邏輯上的概念,只有具體到具體的日誌檔案,才是物理上的概念。
我們看最右邊的部分,檔名都是20位的整數,這個數字稱為訊息的「基準偏移量」。例如我們第二個log segment是從121開始的,那麼代表了這個日誌段的第一條訊息的偏移量是從121開始的,也代表了在這之前有121條日誌記錄。
注意,因為我們的偏移量是從0開始的,所以在121這個偏移量之前有121條資料,而不是120條。
然後我們再聊聊檔案的格式,我們看到這裡有三種型別的檔案,*.log
、*.index
、*.timeindex
。
log格式的檔案記錄了訊息,index是偏移量索引,timeindex是時間戳索引。但是這個我們不展開聊,這篇文章的定位還是偏向於了解各個元件。
如此一來,broker在接收到生產者發過來的訊息的時候,需要將訊息寫在最後的log segment中。這樣還帶來了乙個好處,訊息的寫入是順序的io。也因為如此,最後的乙個log segment,被稱為「active log segment」。
同樣在本文中,我們將更深入更準確的了解位於kafka中的「消費者」。
其實在kafka中,消費者是以消費者組的形式對外消費的。
我們作乙個假設,假設沒有消費者組這種概念,我們現在有10個消費者訂閱了同乙個主題,那麼當這個主題有新的訊息之後,我們這10個消費者是不是應該去「搶訊息」進行消費呢?
這是一種浪費資源的表現。
所以消費者組,也可以認為是一種更加合理分配資源,進行負載均衡的設計。
假設有5個消費者屬於同乙個消費者組,這個消費者組訂閱了乙個具有10個分割槽的主題,那麼組內的每乙個消費者,都會負責處理2個分割槽的訊息。
這樣,能夠保證當一條訊息傳送到主題中,只會被乙個消費者所消費,不會造成重複消費的情況。
此外,消費者組的設計還能夠令我們很方便的橫向擴充套件系統的消費能力。設想一下在我們發覺系統中訊息堆積越來越多,消費速度跟不上生產速度的時候,只需要新增消費者,並且將這個消費者劃入原來的消費者組中,kafka會自動調整組內消費者對分割槽的分配,這個過程稱為重平衡,我們在後面會提到。
但是需要注意的是,組內消費者的數量不能超過主題的分割槽數目。否則,多出的消費者將會空閒。例如乙個主題具有10個分割槽,而組內有11個消費者,那麼這多出來的乙個消費者將空閒。
kafka這樣的設計是為了同乙個分割槽只能夠被乙個消費者所消費,這個跟位移管理有關,我們在後文會提到。
另外,kafka還支援多個消費者組訂閱同乙個主題,這樣,相同的訊息將被傳送到所有訂閱了這個主題的消費者組中。
注意:我們說到了同一分割槽只能被同乙個消費者消費,但是這個說法的前提是這些消費者位於同乙個消費者組。也就是說,不同消費者組內的消費者,是可以消費同乙個主題分割槽的。
所以,我們也可以認為kafka的消費者組,是為了實現點對點以及廣播這兩種方式的訊息傳遞。
我們在上乙個小節提到了消費者組內的消費者對分區內的資訊進行消費,並且存在了消費者的加入與退出這種情況。
所以在這節我們來聊聊kafka是怎麼做到在消費者有變動的情況下,訊息不會丟失或者重複消費。
我們可以很容易的想到,只要記錄下消費過的位移,就能夠實現上述的目標了。
我們直接聊聊位移主題這種方式,不管以前的將位移儲存在zk中的實現方式。
在kafka中有一種特殊的主題,稱為位移主題,在kafka中的主題名稱是__consumer_offsets
。
因為位移主題也是乙個主題,所以也符合kafka中主題的各種特性,我們可以隨意的傳送訊息,拉取訊息,刪除主題。但是因為這個主題的資料是kafka設計好的,所以不能隨意的傳送訊息過去,否則在broker端不能解析的話,就會造成崩潰。
然後我們討論一下發往位移主題的訊息格式。因為我們是希望儲存位移,所以很容易會想到這是乙個kv結構。那麼key中應該儲存哪些訊息呢?
key中包含了主題名,分割槽名,消費者組名。
其實在這裡是不需要儲存消費者id之類的資訊的,也就是說只需要具體到是哪個消費者組在哪個主題的哪個分割槽消費了多少資料,就足夠了。為什麼呢?因為我們上文也提到了,消費者是可能發生變動的,我們的目的是讓消費者發生變動後,能知道從**繼續消費。因此,位移資訊的精確度到消費者組級別,就足夠了。
並且,在value中,只需要儲存消費位移,就足夠了。
說完了位移資訊是怎麼儲存的,我們再來聊聊位移主題本身。因為位移主題也是乙個主題,所以必然也會有分割槽,也會有副本。那麼消費者在消費了資訊之後,該把位移傳送到哪呢?
kafka中的位移主題會在第乙個消費者被建立的時候建立,缺省會有50個分割槽。消費者在提交位移的時候,會根據自己組id的hash值模位移主題的分割槽數,所得到的結果就是位移資訊該提交的分割槽id,然後找到這個分割槽id的leader節點,將位移資訊提交到這個leader節點所在的broker中。
聊了位移主題,我想你大概明白kafka關於位移狀態的儲存了,那麼在這一節中,我們來聊聊位移是怎麼被提交的。
在說到位移的提交之前需要明確的是:雖然有了位移主題這樣的設計,但是並不代表了訊息一定不會被重複消費,也不代表訊息一定不會丟失。
另外,kafka會嚴格的執行位移主題中所提交的資訊。例如已經消費了0-20的訊息,如果你提交的位移是100,那麼下一次拉取的資訊一定是從100開始的,20-99的訊息將會丟失。又比如你提交的位移是10,那麼10-20的訊息將會被重複消費。
在kafka中,位移的提交有兩種方式,一種是自動提交,一種是手動提交。
位移的自動提交是在poll操作的時候進行的。
在消費者poll拉取最新的訊息之前,會先判斷目前是否已經到了提交位移的deadline時間點,如果已經到了這個時間,則先進行位移的提交,然後再拉取資訊。
注意,這裡可能會發生如下的情況:
在某一時刻提交了位移100,隨後你拉取了100-150的訊息,但是還沒有到下一次提交位移的時候,消費者宕機了。可能這個時候只消費了100-120的訊息,那麼在消費者重啟後,因為120的位移沒有提交,所以這部分的訊息會被重複消費一次。
再設想一種情況,你拉取了100-150的訊息,這個時候到了自動提交的時間,提交了150的這個位移,而這個時候消費者宕機了,重啟之後會從150開始拉取資訊處理,那麼在這之前的資訊將會丟失。
對於因為自動提交而造成的資訊丟失和重複消費,你可以採取手動提交的方式來避免。
手動提交又分為同步提交和非同步提交兩種提交方式。
同步提交會直到訊息被寫入了位移主題,才會返回,這樣是安全的,但是可能造成的問題是tps降低。
非同步提交是觸發了提交這個操作,就會返回。這樣速度是很快的,但是可能會造成提交失敗的情況。
我們在上面的內容中提到過這麼一種情況:
消費者組內的成員增減,導致組內的成員需要重新調整他需要負責的消費的分割槽。
這種情況我們稱為「rebalance」,或者稱為「重平衡」。
用專業一點的話來下定義就是:某個消費組內的消費者就如何消費某個主題的所有分割槽達成乙個共識的過程。
但是這個過程對kafka的吞吐率影響是巨大的,因為這個過程有點像gc中的stw(世界停止),在rebalance的時候,所有的消費者只能去做重平衡這一件事情,不能消費任何的訊息。
下面我們來說說哪些情況可能會導致rebalance:
而且在rebalance的時候,假設有消費者退出了,導致多出了一些分割槽,kafka並不是把這幾個多出來的分割槽分配給原來的那些消費者,而是所有的消費者一起參與重新分配所有的分割槽。
當有新的消費者加入的時候,也不是原本的每個消費者分出一些分割槽給新的消費者,而是所有的消費者一起參與重新分配所有的分割槽。
這樣的分配策略聽起來就很奇怪且影響效率,但是沒有辦法。
不過社群新推出了stickyassignor(粘性分配)策略,就可以做到我們上面假設的情況,但是目前還存在一些bug。
首先,謝謝你能看到這裡!
關於kafka的前兩篇文章,我認為都是科普性質的,希望可以用比較簡單的方式給你梳理一遍kafka具有的功能,以及各個功能的運作方式。
在後面的文章中,我也希望能夠比較清晰易懂的給你介紹kafka的一些原理之類的東西。
再次感謝你能看到這裡!
Kafka 消費者 位移提交
kafka位移機制 broker維護消費者的消費位移資訊,老的版本儲存在zk上,新版本儲存在內部的topic裡。本質上,位移資訊消費者自己維護也可以,但是如果消費者掛了或者重啟,對於某乙個分割槽的消費位移不就丟失了嗎?所以,還是需要提交到broker端做持久化的。提交方式分為自動和手動。自動是預設的...
Kafka學習之旅 十五 重設消費者組位移
簡介 相信大家也遇到過需要重某個位置或者時間點重新消費的情況那麼本篇講下重新設定消費組位移。kafka 乙個比較有特色的設計是由於它是基於日誌結構 log based 的訊息引擎,消費者在消費訊息時,僅僅是從磁碟檔案上讀取資料而已,是唯讀的操作,因此消費者不會刪除訊息資料。同時,由於位移資料是由消費...
任務4 04 Kafka入門 消費模式
訊息佇列的兩種模式 點對點模式 一對一,訊息只能給乙個人,比較單一。明顯感覺到點對點的模式缺點 就是不可復用,加入這個訊息需要給多個人處理,就會很麻煩,flume可以給多個,但是需要多個channel和多個sink 點對點模式如果要復用,就必須發給多個訊息佇列,然後消費者再去接收。浪費資源。這裡強調...