1. 程式人生 > >rocketmq怎麼保證佇列完全順序消費

rocketmq怎麼保證佇列完全順序消費

原文:https://www.zhihu.com/question/30195969

實際上,RocketMQ是支援順序消費的。

但這個順序,不是全域性順序,只是分割槽順序。要全域性順序只能一個分割槽。

之所以出現你這個場景看起來不是順序的,是因為傳送訊息的時候,訊息傳送預設是會採用輪詢的方式傳送到不通的queue(分割槽)。如圖:



而消費端消費的時候,是會分配到多個queue的,多個queue是同時拉取提交消費。

如圖:




但是同一條queue裡面,RocketMQ的確是能保證FIFO的。那麼要做到順序訊息,應該怎麼實現呢——把訊息確保投遞到同一條queue。

rocketmq訊息生產端示例程式碼如下:



按照這個示例,把訂單號取了做了一個取模運算再丟到selector中,selector保證同一個模的都會投遞到同一條queue。

即: 相同訂單號的--->有相同的模--->有相同的queue。

最後就會類似這樣:



這樣同一批你需要做到順序消費的肯定會投遞到同一個queue,同一個queue肯定會投遞到同一個消費例項,同一個消費例項肯定是順序拉取並順序提交執行緒池的,只要保證消費端順序消費,則大功告成!

如何保證順序消費? 如果是使用MessageListenerOrderly則自帶此實現,如果是使用MessageListenerConcurrently,則需要把執行緒池改為單執行緒模式。

(這裡假設觸發了重排導致queue分配給了別人也沒關係,由於queue的訊息永遠是FIFO,最多隻是已經消費的訊息重複而已,queue內順序還是能保證)

但的確會有一些異常場景會導致亂序。如master宕機,導致寫入佇列的數量上出現變化。

如果還是沿用取模的seletor,就會一批訂單號的訊息前面雜湊到q0,後面的可能散到q1,這樣就不能保證順序了。除非選擇犧牲failover特性,如master掛了無法發通接下來那批訊息。

從消費端,如果想保證這批訊息是M1消費完成再消費M2的話,可以使用MessageListenerOrderly介面,但是這樣的話會有以下問題:

1. 遇到訊息失敗的訊息,無法跳過,當前佇列消費暫停2. 目前版本的RocketMQ的MessageListenerOrderly是不能從slave消費訊息的。


更多分析請參考: