RocketMQ如何保證隊列完全順序消費


在知乎看到了這個問題,總結下(發現某乎社會熱點問題討論沒法看,專業知識問題老哥們答得可是很ok)

首先,根據RocketMQ的存儲機制,RocketMQ是支持順序消費的。但這個順序,不是全局順序,只是分區(Message Queue)順序。要全局順序只能一個分區(Message Queue)。

接下來,我們從生產者和消費者兩方面的邏輯來考慮這個問題。

Consumer

消費消息的順序要同發送消息的順序一致。由於 Consumer 消費消息的時候是針對 Message Queue 順序拉取並開始消費,且一條 Message Queue 只會給一個消費者(集群模式下)(一個Topic的多個隊列分配給一個group,然后group的多個消費者各自分到隊列進行消費,默認平均分配),所以能夠保證同一個消費者實例對於 Queue 上消息的消費是順序地開始消費(不一定順序消費完成,因為消費可能並行)。

Producer

發送消息的時候,消息發送默認是會采用輪詢的方式發送到不同的queue,需要的話生產者發送的時候可以用 MessageQueueSelector 為某一批消息(通常是有相同的唯一標示id)選擇同一個 Queue ,則這一批消息的消費將是順序消息(並由同一個consumer完成消息)。或者 Message Queue 的數量只有 1 ,但這樣消費的實例只能有一個,多出來的實例都會空跑。

但的確會有一些異常場景會導致亂序。如Broker 宕機或重啟,導致寫入隊列的數量上出現變化。這樣在MessageQueueSelector之中的邏輯無論是輪訓還是取模就會出問題,由於隊列總數發生發化,消費者也會觸發負載均衡,而默認地負載均衡算法采取哈希取模平均,這樣負載均衡分配到定位的隊列會發化,使得隊列可能分配到別的實例上,則會短暫地出現消息順序不一致。除非選擇犧牲failover特性(即 Broker 集群中只要有一台機器不可用,則整個集群都不可用),如master掛了無法發通接下來那批消息,但是服務可用性大大降低。

討論完順序消費的邏輯,我們來看一看實際場景中的問題,擴容是我們可能會遇到的場景,我們來思考下在擴容情況下,如何在不停寫的情況下保證順序消費?

順序消息擴容的過程中,如何在不停寫的情況下保證消息順序?

1成倍擴容,實現擴容前后,同樣的 key,hash 到原隊列,或者 hash 到新擴容的隊列。

2擴容前,記錄舊隊列中的最大位點。

3對於每個 Consumer Group ,保證舊隊列中的數據消費完,再消費新隊列,也即:先對新隊列進行禁讀即可。

參考資料

rocketmq怎么保證隊列完全順序消費?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM