當集群中有新成員加入,或者某些主題增加了分區之后,消費者是怎么進行重新分配消費的?這里就涉及到重平衡(Rebalance)的概念,下面我就給大家講解一下什么是 Kafka 重平衡機制,我盡量做到圖文並茂通俗易懂。
重平衡的作用
重平衡跟消費組緊密相關,它保證了消費組成員分配分區可以做到公平分配,也是消費組模型的實現,消費組模型如下:
從圖中可以找到消費組模型的幾個概念:
- 同一個消費組,一個分區只能被一個消費者訂閱消費,但一個消費者可訂閱多個分區,也即是每條消息只會被同一個消費組的某一個消費者消費,確保不會被重復消費;
- 一個分區可被不同消費組訂閱,這里有種特殊情況,加入每個消費組只有一個消費者,這樣分區就會廣播到所有消費者上,實現廣播模式消費。
要想實現以上消費組模型,那么就要實現當外部環境變化時,比如主題新增了分區,消費組有新成員加入等情況,實現動態調整以維持以上模型,那么這個工作就會交給 Kafka 重平衡機制去處理。
Kafka與RocketMQ的重平衡區別
Kafka 重平衡機制的一些實現相比 RocketMQ 還是有些區別的,但最終的目的還是都是一樣,就是保證分區(RocketMQ 是隊列)公平分配且只能被一個消費者訂閱(同一個消費組)。
Kafka 重平衡:
從圖中可看出,Kafka 重平衡是外部觸發導致的,觸發 Kafka 重平衡的有以下幾種情況:
- 消費組成員發生變更,有新消費者加入或者離開,或者有消費者崩潰;
- 消費組訂閱的主題數量發生變更;
- 消費組訂閱的分區數發生變更。
每個消費者都會跟 Coordinator 保持心跳,當以上情況發生時,心跳響應就會包含 REBALANCE_IN_PROGRESS 命令,消費者停止消費,加入到重平衡事件當中。
RocketMQ重平衡:
RocketMQ 消費者啟動時,會開啟兩條線程,一條線程執行拉取消息任務,另一條線程者則定時執行重平衡任務,從圖中可看出拉取消息線程會從 pullRequestQueue 中取出拉取任務,pullRequestQueue 是一個阻塞隊列,意味着當 pullRequestQueue 隊列中元素為空時,會一直阻塞,直到有新的拉取任務,那么如果添加新的任務到阻塞隊列中去呢?這時 RocketMQ 的重平衡作用就來了,它會每隔 20s 從任意一個 Broker 節點獲取消費組的消費 ID 以及訂閱信息,再根據這些訂閱信息進行分配,然后將分配到的信息封裝成 pullRequest 對象 pull 到 pullRequestQueue 隊列中,拉取線程喚醒后執行拉取任務。
重平衡所涉及的參數
在消費者啟動時,某些參數會影響重平衡機制的發生,所以需要根據業務的屬性,對這些參數進行調優,否則可能會因為設置不當導致頻繁重平衡,嚴重影響消費速度,下面跟大家說說這幾個參數的一些要點:
- session.timeout.ms
該參數是 Coordinator 檢測消費者失敗的時間,即在這段時間內客戶端是否跟 Coordinator 保持心跳,如果該參數設置數值小,可以更早發現消費者崩潰的信息,從而更快地開啟重平衡,避免消費滯后,但是這也會導致頻繁重平衡,這要根據實際業務來衡量。
- max.poll.interval.ms
消費者處理消息邏輯的最大時間,對於某些業務來說,處理消息可能需要很長時間,比如需要 1分鍾,那么該參數就需要設置成大於 1分鍾的值,否則就會被 Coordinator 剔除消息組然后重平衡。
- heartbeat.interval.ms
該參數跟 session.timeout.ms 緊密關聯,前面也說過,只要在 session.timeout.ms 時間內與 Coordinator 保持心跳,就不會被 Coordinator 剔除,那么心跳間隔的時間就是 session.timeout.ms,因此,該參數值必須小於 session.timeout.ms,以保持 session.timeout.ms 時間內有心跳。
下面我用圖來形象表達這三個參數的含義:
重平衡流程
在新版本中,消費組的協調管理已經依賴於 Broker 端某個節點,該節點即是該消費組的 Coordinator, 並且每個消費組有且只有一個 Coordinator,它負責消費組內所有的事務協調,其中包括分區分配,重平衡觸發,消費者離開與剔除等等,整個消費組都會被 Coordinator 管控着,在每個過程中,消費組都有一個狀態,Kafka 為消費組定義了 5 個狀態,如下:
- Empty:消費組沒有一個活躍的消費者;
- PreparingRebalance:消費組准備進行重平衡,此時的消費組可能已經接受了部分消費者加入組請求;
- AwaitingSync:全部消費者都已經加入組並且正在進行重平衡,各個消費者等待 Broker 分配分區方案;
- Stable:分區方案已經全部發送給消費者,消費者已經在正常消費;
- Dead:該消費組被 Coordinator 徹底廢棄。
可以看出,重平衡發生在 PreparingRebalance 和 AwaitingSync 狀態機中,重平衡主要包括以下兩個步驟:
- 加入組(JoinGroup):當消費者心跳包響應 REBALANCE_IN_PROGRESS 時,說明消費組正在重平衡,此時消費者會停止消費,並且發送請求加入消費組;
- 同步更新分配方案:當 Coordinator 收到所有組內成員的加入組請求后,會選出一個consumer Leader,然后讓consumer Leader進行分配,分配完后會將分配方案放入SyncGroup請求中發送會Coordinator,Coordinator根據分配方案發送給每個消費者。
重平衡場景舉例
根據重平衡觸發的條件,重平衡的工作流程大概有以下幾種類型:
有新的成員加入消費組:
消費組成員崩潰
消費組成員主動離開
消費組成員提交位移時