微信公眾號「后端進(jìn)階」迷郑,專注后端技術(shù)分享:Java创倔、Golang畦攘、WEB框架、分布式中間件叹螟、服務(wù)治理等等台盯。
當(dāng)集群中有新成員加入,或者某些主題增加了分區(qū)之后良价,消費(fèi)者是怎么進(jìn)行重新分配消費(fèi)的蒿叠?這里就涉及到重平衡(Rebalance)的概念,下面我就給大家講解一下什么是 Kafka 重平衡機(jī)制痊银,我盡量做到圖文并茂通俗易懂施绎。
重平衡的作用
重平衡跟消費(fèi)組緊密相關(guān)粘姜,它保證了消費(fèi)組成員分配分區(qū)可以做到公平分配,也是消費(fèi)組模型的實(shí)現(xiàn)孤紧,消費(fèi)組模型如下:
從圖中可以找到消費(fèi)組模型的幾個(gè)概念:
- 同一個(gè)消費(fèi)組,一個(gè)分區(qū)只能被一個(gè)消費(fèi)者訂閱消費(fèi)躺酒,但一個(gè)消費(fèi)者可訂閱多個(gè)分區(qū)蔑歌,也即是每條消息只會被同一個(gè)消費(fèi)組的某一個(gè)消費(fèi)者消費(fèi),確保不會被重復(fù)消費(fèi)园匹;
- 一個(gè)分區(qū)可被不同消費(fèi)組訂閱劫灶,這里有種特殊情況,加入每個(gè)消費(fèi)組只有一個(gè)消費(fèi)者本昏,這樣分區(qū)就會廣播到所有消費(fèi)者上涌穆,實(shí)現(xiàn)廣播模式消費(fèi)。
要想實(shí)現(xiàn)以上消費(fèi)組模型趁舀,那么就要實(shí)現(xiàn)當(dāng)外部環(huán)境變化時(shí)原叮,比如主題新增了分區(qū)巡蘸,消費(fèi)組有新成員加入等情況悦荒,實(shí)現(xiàn)動態(tài)調(diào)整以維持以上模型,那么這個(gè)工作就會交給 Kafka 重平衡機(jī)制去處理搬味。
Kafka與RocketMQ的重平衡區(qū)別
Kafka 重平衡機(jī)制的一些實(shí)現(xiàn)相比 RocketMQ 還是有些區(qū)別的碰纬,但最終的目的還是都是一樣,就是保證分區(qū)(RocketMQ 是隊(duì)列)公平分配且只能被一個(gè)消費(fèi)者訂閱(同一個(gè)消費(fèi)組)寿桨。
Kafka 重平衡:
從圖中可看出强戴,Kafka 重平衡是外部觸發(fā)導(dǎo)致的,觸發(fā) Kafka 重平衡的有以下幾種情況:
- 消費(fèi)組成員發(fā)生變更预烙,有新消費(fèi)者加入或者離開扁掸,或者有消費(fèi)者崩潰;
- 消費(fèi)組訂閱的主題數(shù)量發(fā)生變更炼蹦;
- 消費(fèi)組訂閱的分區(qū)數(shù)發(fā)生變更狸剃。
每個(gè)消費(fèi)者都會跟 Coordinator 保持心跳,當(dāng)以上情況發(fā)生時(shí)虑省,心跳響應(yīng)就會包含 REBALANCE_IN_PROGRESS 命令僧凰,消費(fèi)者停止消費(fèi)训措,加入到重平衡事件當(dāng)中。
RocketMQ重平衡:
RocketMQ 消費(fèi)者啟動時(shí)怀大,會開啟兩條線程呀闻,一條線程執(zhí)行拉取消息任務(wù),另一條線程者則定時(shí)執(zhí)行重平衡任務(wù)蓖康,從圖中可看出拉取消息線程會從 pullRequestQueue 中取出拉取任務(wù)垒手,pullRequestQueue 是一個(gè)阻塞隊(duì)列科贬,意味著當(dāng) pullRequestQueue 隊(duì)列中元素為空時(shí),會一直阻塞鸭丛,直到有新的拉取任務(wù),那么如果添加新的任務(wù)到阻塞隊(duì)列中去呢瘾带?這時(shí) RocketMQ 的重平衡作用就來了熟菲,它會每隔 20s 從任意一個(gè) Broker 節(jié)點(diǎn)獲取消費(fèi)組的消費(fèi) ID 以及訂閱信息,再根據(jù)這些訂閱信息進(jìn)行分配允蚣,然后將分配到的信息封裝成 pullRequest 對象 pull 到 pullRequestQueue 隊(duì)列中呆贿,拉取線程喚醒后執(zhí)行拉取任務(wù)。
重平衡所涉及的參數(shù)
在消費(fèi)者啟動時(shí)冒晰,某些參數(shù)會影響重平衡機(jī)制的發(fā)生壶运,所以需要根據(jù)業(yè)務(wù)的屬性浪秘,對這些參數(shù)進(jìn)行調(diào)優(yōu),否則可能會因?yàn)樵O(shè)置不當(dāng)導(dǎo)致頻繁重平衡棵癣,嚴(yán)重影響消費(fèi)速度违帆,下面跟大家說說這幾個(gè)參數(shù)的一些要點(diǎn):
- session.timeout.ms
該參數(shù)是 Coordinator 檢測消費(fèi)者失敗的時(shí)間刷后,即在這段時(shí)間內(nèi)客戶端是否跟 Coordinator 保持心跳渊抄,如果該參數(shù)設(shè)置數(shù)值小,可以更早發(fā)現(xiàn)消費(fèi)者崩潰的信息含衔,從而更快地開啟重平衡,避免消費(fèi)滯后缓呛,但是這也會導(dǎo)致頻繁重平衡杭隙,這要根據(jù)實(shí)際業(yè)務(wù)來衡量痰憎。
- max.poll.interval.ms
消費(fèi)者處理消息邏輯的最大時(shí)間,對于某些業(yè)務(wù)來說洽沟,處理消息可能需要很長時(shí)間蜗细,比如需要 1分鐘鳄乏,那么該參數(shù)就需要設(shè)置成大于 1分鐘的值,否則就會被 Coordinator 剔除消息組然后重平衡朽缴。
- heartbeat.interval.ms
該參數(shù)跟 session.timeout.ms 緊密關(guān)聯(lián)水援,前面也說過,只要在 session.timeout.ms 時(shí)間內(nèi)與 Coordinator 保持心跳或渤,就不會被 Coordinator 剔除奕扣,那么心跳間隔的時(shí)間就是 session.timeout.ms惯豆,因此,該參數(shù)值必須小于 session.timeout.ms地熄,以保持 session.timeout.ms 時(shí)間內(nèi)有心跳芯杀。
下面我用圖來形象表達(dá)這三個(gè)參數(shù)的含義:
重平衡流程
在新版本中,消費(fèi)組的協(xié)調(diào)管理已經(jīng)依賴于 Broker 端某個(gè)節(jié)點(diǎn)扶供,該節(jié)點(diǎn)即是該消費(fèi)組的 Coordinator裂明, 并且每個(gè)消費(fèi)組有且只有一個(gè) Coordinator,它負(fù)責(zé)消費(fèi)組內(nèi)所有的事務(wù)協(xié)調(diào)轰绵,其中包括分區(qū)分配尼荆,重平衡觸發(fā)捅儒,消費(fèi)者離開與剔除等等,整個(gè)消費(fèi)組都會被 Coordinator 管控著鞭莽,在每個(gè)過程中麸祷,消費(fèi)組都有一個(gè)狀態(tài),Kafka 為消費(fèi)組定義了 5 個(gè)狀態(tài)喷面,如下:
- Empty:消費(fèi)組沒有一個(gè)活躍的消費(fèi)者走孽;
- PreparingRebalance:消費(fèi)組準(zhǔn)備進(jìn)行重平衡惧辈,此時(shí)的消費(fèi)組可能已經(jīng)接受了部分消費(fèi)者加入組請求;
- AwaitingSync:全部消費(fèi)者都已經(jīng)加入組并且正在進(jìn)行重平衡磕瓷,各個(gè)消費(fèi)者等待 Broker 分配分區(qū)方案盒齿;
- Stable:分區(qū)方案已經(jīng)全部發(fā)送給消費(fèi)者,消費(fèi)者已經(jīng)在正常消費(fèi)困食;
- Dead:該消費(fèi)組被 Coordinator 徹底廢棄边翁。
可以看出,重平衡發(fā)生在 PreparingRebalance 和 AwaitingSync 狀態(tài)機(jī)中陷舅,重平衡主要包括以下兩個(gè)步驟:
- 加入組(JoinGroup):當(dāng)消費(fèi)者心跳包響應(yīng) REBALANCE_IN_PROGRESS 時(shí)倒彰,說明消費(fèi)組正在重平衡审洞,此時(shí)消費(fèi)者會停止消費(fèi)待讳,并且發(fā)送請求加入消費(fèi)組;
- 同步更新分配方案:當(dāng) Coordinator 收到所有組內(nèi)成員的加入組請求后仰剿,會選出一個(gè)consumer Leader创淡,然后讓consumer Leader進(jìn)行分配,分配完后會將分配方案放入SyncGroup請求中發(fā)送會Coordinator南吮,Coordinator根據(jù)分配方案發(fā)送給每個(gè)消費(fèi)者琳彩。
重平衡場景舉例
根據(jù)重平衡觸發(fā)的條件,重平衡的工作流程大概有以下幾種類型:
有新的成員加入消費(fèi)組:
消費(fèi)組成員崩潰
消費(fèi)組成員主動離開
消費(fèi)組成員提交位移時(shí)
關(guān)注公眾號回復(fù)關(guān)鍵字「后端」免費(fèi)領(lǐng)取后端開發(fā)大禮包!