Kafka 消費者組是什麼?細品消費者組的正邪兩面

Kafka 消費者組是什麼?細品消費者組的正邪兩面

「一面天堂,一面地獄」恐怕是 Kafka 消費者組(Consumer Group)最真實的寫照。


作為 kafka 中一個非常有特色的設計,消費者組為 Kafka 實現了 2 種非常典型的消息模型,其強大的伸縮性為Kafka 的牛 x 立下了汗馬功勞,但是又因為它“臭名昭著”的再均衡(Rebalance),引出了不少難以琢磨的問題,一正一邪,讓人欣喜的同時,又讓人痛恨不已。

1. 消費者組面面觀

消費者組是什麼呢?


消費者組是 Kafka 提供的可擴展且具有容錯性的消費者機制。消費者組是一個包含一個或者多個消費者實例的集合。組內的各個消費者具有相同的 ID,這個 ID 稱為Group ID。組內的所有的消費者協調在一起共同消費訂閱主題(Subsrcibed Topics)的所有分區(Partition)的消息。值得注意的是,某個分區每次只能由組內的一個消費者實例消費。


Kafka 採用的消息模型採用一種改良的發佈-訂閱模型,Kafka 消息傳輸過程如下圖所示。從圖中我們可以看出,一個消費者組共同消費同一個訂閱主題,每個分區只能由組內的一個消費者實例消費。

Kafka 消費者組是什麼?細品消費者組的正邪兩面

圖:Kafka 消息傳輸過程


關於消費者組,我們需要理解以下三個特性:

  • 消費者組包含一個或多個消費者實例。不同的消費者實例可以是一個進程,也可以是同一個進程下的不同線程。
  • Group ID 用於標識消費者組,同時也標識消費者屬於哪個消費者組。
  • 同一時刻,消費者組訂閱主題的任何一個分區都只能由同一個消費者組中的某一個消費者實例消費。當然,不同的消費者組之間互相獨立,互不干涉,消費自由、平等。


那麼一個消費者組應該設置多少個消費者實例呢?


由於同一時刻,消費者組訂閱主題的任何一個分區都只能由同一個消費者組中的某一個消費者實例消費,因此,一個消費者組中消費者實例數應該小於等於訂閱主題的分區數。若消費者實例數大於分區數,多出來的消費者實例就會因為分配不到所要消費的分區而空閒,會造成資源的浪費。最理想的情況是,消費者實例個數剛好等於訂閱主題個數,這樣消費者組的消費者實例就可以剛好一對一消費訂閱主題中的分區。


既然消費者組是由消費者組成的,消費者組就需要管理消費位移,那消費者組是如何管理位移的呢?


在消費者組中,Kafka 採用了將位移保存在 Kafka 內部主題的方法,這個內部主題就是 __consumer_offsets。 Kafka 的消費者組將消費位移保存在 Broker 端的內部主題 __consumer_offsets 中。

2. 消費者組的正與邪

與 Kafka 相比,傳統的消息隊列有個問題,那就是消息一旦消費,就會從隊列中刪除,而且只能被下游的一個消費者消費,因此這種模型的伸縮性很差,不能通過擴展消費者實例的個數來增大消費端的消費能力,俗話說的好:“一個好漢三個幫”,沒有兄弟幫忙,消費端怎麼能提高消費能力呢?而常規的發佈-訂閱模型倒是允許消息被多個消費者消費,但是它的問題也是伸縮性不高,因為每個消費者都需要訂閱主題的所有分區。這種全量訂閱的方式既不靈活,也會影響消息的傳遞效果。這就像是一個相親的兄弟來相親會場找女朋友,結果他還需要和其他男生打好關係,這不是多此一舉嗎?


Kafka 的消費者組很好的解決了上述問題。消費者組訂閱了多個不同的主題之後,並不要求組內的每個消費者實例都訂閱所有的分區,不同消費者只需要消費其中的部分分區就好了。消息發送到 Broker 端之後,並不會刪除,而是將消息持久化,因此可以供多個消費者消費。不同的消費者組之間互相獨立,互不干涉,消費自由、平等。


從某種程度上說,Kafka 通過消費者組實現了兩種典型的消息模型:如果所有的消費者實例都屬於同一個消費者組,那麼它實現的就是消息隊列模型;如果所有實例屬於不同的消費者組,那麼它實現的就是典型的發佈-訂閱模式,因此,Kafka 可以說採用了一種改良的發佈-訂閱模型。


2.1 消費者組的正


消費者組是

用於實現高伸縮性、高容錯性的消費者機制。那消費者組是如何實現高容錯性和高伸縮性的呢?


消費者組通過再平衡(Rebalance) 機制實現了高容錯性和高伸縮性。Rebalance 本質上是一種協議,規定了一個消費者組下的所有消費者如何分配訂閱主題的每個分區。


消費者組內多個消費者實例可以同時讀取 Kafka 消息,一旦某個消費者實例“掛了”,消費者組會立即將已經崩潰的消費者移除,並且將其負責的分區交給組內其他的消費者實例來負責,從而保證整個消費者組可以正常消費所訂閱的主題,不會丟失消息,這個過程就稱為“再平衡”。消費者組通過再平衡機制實現了Kafka的高容錯性。


假設某個消費者組有2個消費者,分別是消費者1,消費者2,其中,消費者1負責 topic1-0分區、topic2-1分區和topic3-0分區,消費者2負責topic1-1分區、topic2-0分區和topic3-1分區,但是由於消息量巨大,因此需要引入消費者3。引入之後,就會觸發再平衡,並且根據默認的分配策略重新給三個消費者實例分配負責的分區,每個消費者實例負責2個分區。消費者組通過這種再平衡的方式實現了Kafka的高伸縮性。


2.2 消費者組的邪


消費者組的名聲正是來自於大名鼎鼎的再平衡,但是,也正是再平衡的“臭名昭著”讓消費者組“臭名遠揚“。


為什麼這麼說呢?


首先,再平衡的過程會停止消費者組所有成員的消費過程。在再平衡的過程中,所有的消費者實例全部都會停止消費,stop the world(STW),直到再平衡完成,才會恢復消息進程,這個過程會對消費者組的消費過程造成很大影響。


其次,再平衡的時候所有的消費者實例均需要參與其中,全部重新分配所有分區。這個過程其實做了很多無用功,事實上,儘量減少各個消費者實例所分配的分區的變動才是最優的方案,而不是全部重新洗牌,這樣的話,就會節省很多資源和時間。例如,消費者1原本負責消費分區1、2、3,那麼再平衡之後也應該接著消費1、2、3,而不是重新分配其他分區,這樣的話,消費者1連接這些分區所在的Broker的 TCP 連接就可以繼續用了,不僅節省了資源,也減少了時間。


最後,再平衡的速度實在是太慢了。上百個消費者實例的消費者組再平衡一次很可能需要幾個小時,這是難以忍受的。


3. 總結

正所謂「成也蕭何,敗也蕭何」,再平衡幫助消費者組實現了高伸縮性、高容錯性的消費者機制但是反過來,又嚴重影響了消費者組的消費過程以及消費速率,造成了很多莫名其妙的bug。


消費者組依靠再平衡機制名揚天下,也因為再平衡機制“臭名遠揚“,這個亦正亦邪的消費者組,恐怕也只有我們完全掌握了,才能真正成為一把利刃。


分享到:


相關文章: