一篇文章帶你走近RocketMq

1.相關模塊

1.1 Producer

將消息發送到Broker

1.2 Producer組

發送同一種消息的Produder就可以構成一個Producer集羣。同一種消息指的是消息的Topic和Tag相同

1.3 Consumer

Broker將消息投遞到Consumer

1.4 Consumer組

同一個GroupName,並且訂閱同一個Topic下的同中Tag的Consumer,就可以構成一個Consumer組。

1.5 NameServer(可集羣)

維護集羣中所有的節點信息,類似於dubbo中的zk。和Broker每個節點建立長連接,利用心跳機制獲取Broker集羣中的可用節點,並缺獲取Broker中的Topic信息。Producer會和NameServer中隨機一個節點建立連接,獲取Topic信息。Producer發送消息時,通過NameServer提供的信息,找到Topic對應的的Broker,建立長連接,這個Broker只能是Master節點。Consumer會和NameServer中的隨機一個節點建立連接,獲取Topic信息。Consumer會根據NameServer提供的信息,找到訂閱的Topic對應的Broker,建立長連接。這個Broker可以是Master節點,也可以是Slaver節點。

1.6 Broker(可集羣)

Broker接受來自Producer的消息並存儲,投遞消息給消費者。內部有Topic的概念,一個Topic中可對應多個Queue。Queue對應Consumer端來說是透明的。

Broker內部是可以集羣的,分爲Master和Slaver,類似與Mysql的Master和Slaver。

1.7 Message

消息實體,在MQ中進行傳輸的就是Message,Message有Topic和Tag的概念。通過Topic,Producer就可以知道消息要發送到哪個Broker。Consumer在創建時需要訂閱指定的Topic和Tag,通過Topic和對應的Broker建立連接。Broker投遞時,再根據Tag推送消息到Consumer中。

1.8 關係圖

 

6332814-fbe6608f3e164f55.png                                           ​

 

2.部署方式

2.1 單master

只有一個節點,該節點掛掉,整個服務將不可用。部署比較簡單,但有單點問題。

2.2 多master

多個master組成集羣,單個master掛掉對集羣沒有影響。需要開啓同步刷盤模式,來保證某個節點掛掉時消息不丟失,Topic也需要均勻分佈在每Master上,保證某個節點掛了,還能提供服務。

2.3 多master,多slaver異步複製

多個master對應多個slaver,master提供讀寫功能,slaver提供讀功能,master和slaver之間通過異步複製保證數據的同步,類似mysql的主從模式。不過可能會存在消息丟失情況,master掛掉時,對應的數據還沒有同步到slaver上。

2.4 多master,多slaver同步雙寫

多個master對應多個slaver,和異步複製的區別是。數據同步的方式是同步的,保證master和slaver的數據一致,這樣就會導致發送消息的響應時間較異步複製長一點,不過能夠保證消息不丟失。

 

3.消息類型

3.1 普通消息

消息只管往broker裏面丟,不保證consumer端消費的順序性

3.2 有序消息

保證consumer消費時的順序性,特定的一些場景下必須使用有序消息來實現。比如訂單的創建,付款和完成。有序消息又分爲全局有序和局部有序。

全局有序:一個Topic中只創建一個Queue,所有的消息都丟到這個Queue中,就能保證消費端消費的有序,不過吞吐量很低。

局部有序: 一個Topic中可以創建多個Queue,思想就是保證同一個對象的不同事件都得落在同一個Queue上。建議通過hash取模的方式來做,即可以保證一個對象的不同時間在一個queue,也可以保證每個queue的充分利用。

3.3 延時消息

消息發送到broker中,不會立即投遞到consumer,而是會等待到指定時間再進行投遞。RcoketMQ的延時等級爲:1s,5s,10s,30s,1m,2m,3m,4m,5m,6m,7m,8m,9m,10m,20m,30m,1h,2h。level=0,表示不延時。level=1,表示 1 級延時,對應延時 1s。level=2 表示 2 級延時,對應5s,以此類推。

 

4.消息發送方式

4.1 同步發送 

producer發送消息到broker後,需要等待broker響應,再發送下一條消息,類似於TCP中的停止等待ARQ。可以保證消息的實時可靠性,比如通知郵件,營銷短信。

4.2 異步發送

producer發送消息到broker後,不需要等待broker響應,可以繼續發送下一條消息,不過broker還是會給producer響應,類似於TCP的連續等待ARQ。比如需要花一些時間處理完再給響應的,也是可以保證消息的可靠性,不過不是實時的。

4.3 單向發送

producer只管發送消息給broker,不管收不收到響應,不能保證消息的可靠性。特點就是快,使用於耗時短,可靠性要求不高的場景

 

5.消息消費模式

當一堆consumer實例使用同一個group name,並且訂閱的Topic和Tag一樣時,才構成一個Consumer集羣。

5.1 集羣消費

consumer 的消費進度是存儲在 broker 上,consumer 自身不存儲消費進度。每條消息只會被 consumer 集羣內的任意一個 consumer 實例消費一次。比如有3個consumer,消息如果投遞到其中一個被正常消費,那麼這個消息就算被消費了,其他兩個consumer不會消費的這個消息。集羣消費模式提供消息重投機制,廣播消費則沒有,不過消費重投不能保證重投的消息還是投遞到之前消費失敗的那一臺機器上。

5.2 廣播消費

與集羣消費不同,consumer 的消費進度是存儲在各個 consumer 實例上。消息會被推送到相關的所有consumer上,比如又3個consumer,消息會投遞到這3個consumer上,不管消費成不成功。而且不會進行消費失敗重投,所以在 consumer 端消費邏輯處理時,需要額外關注消費失敗的情況。

5.3 集羣模擬廣播消費

如果業務上確實需要使用廣播消費,但又想利用消息重投機制。可以通過創建多個 consumer 實例,每個 consumer 實例屬於不同的 consumer group,但是它們都訂閱同一個 topic。比如:有3個consumer,這3個consumer屬於不同的group,但它們都訂閱topic A。當broker要投遞消息時,這3個consumer都能收到消息。

每個consumer的消費邏輯可以一樣,也可以不一樣。每個consumer group還可以根據需要增加內部的consumer實例。

 

6.刷盤方式

 RocketMQ的消息是存儲到磁盤上的,這樣既能保證斷電後恢復,又可以讓存儲的消息量超出內存的限制。

RocketMQ爲了提高性能,會盡可能地保證磁盤的順序寫。

6.1 異步刷盤

在返回寫成功狀態時,消息可能只是被寫入了內存的PAGECACHE,寫操作的返回快,吞吐量大。當內存裏的消息量積累到一定程度時,統一觸發寫磁盤操作,快速寫入。缺點是可能導致數據丟失,在數據還沒有被寫入磁盤,機器宕機,就會丟失數據。

6.2 同步刷盤

在返回寫成功狀態時,消息已經被寫入磁盤。具體流程是,消息寫入內存的PAGECACHE後,立刻通知刷盤線程刷盤,然後等待刷盤完成,刷盤線程執行完成後喚醒等待的線程,返回消息寫成功的狀態。缺點是磁盤io次數多,效率較低,響應時間較長。

6.3 生產應用

在生產中,一般使用異步刷盤方式,來增大系統吞吐量。通過broker主從數據同步雙寫來保證數據不被丟失。

 

7.小細節

7.1 消息過濾

利用tag機制,可以實現消息過濾。我們在發送消息時,可以給message打上tag,在consumer訂閱時,指定對應的topic中的特定tag,就可以實現消費端的消息過濾。比如:創建一個Trade的Topic,producer在發送Trade的消息時,可以打上order,pay,logistic的tag。關於訂單的consumer指定order的tag,關於支付的consumer指定pay的tag,關於物流的consumer指定logistic的tag。

7.2 訂閱關係一致性

訂閱關係一致性指的是同一個Consumer group中,每一個consumer訂閱的topic和tag必須相同,才能稱之爲一個Consumer group。要保證訂閱關係一致性,就必須同時保證兩點。1.訂閱的topic一致 2.訂閱的tag也必須一致

比如: consumer1訂閱了 topic A的tag a || tag b,consumer2也訂閱了topic A的tag a || tag b。這兩個consumer就可以稱之爲一個consumer group

7.3 消息重試

消息重試只針對集羣消費模式,那麼什麼是消息重試呢?簡單來說,就是當消費者消費消息失敗後,broker 會重新投遞該消息,直到消費成功。消費失敗的情況有3種。

1.返回 ConsumeConcurrentlyStatus.RECONSUME_LATER

2.返回null

3.拋出異常。需要注意的是,如果異常被在消費時發生的異常如果被捕獲,是不會重試的。

 

此外,消息也不會無限重試,因爲可能存在一些髒數據或者bug,無論重試多少次都失敗。所以,RocketMq提供了一個重試機制:

第幾次重試 每次重試間隔時間
1 10 秒
2 30 秒
3 1 分鐘
4 2 分鐘
5 3 分鐘
6 4 分鐘
7 5 分鐘
8 6 分鐘
9 7 分鐘
10 8 分鐘
11 9 分鐘
12 10 分鐘
13 20 分鐘
14 30 分鐘
15 1 小時
16 2 小時

如果重投次數超過了16次,那麼消息就不會再投遞給消費者,而是將消息放到相對應的死信隊列中。這時候我們就需要對死信隊列的消息做一些人工補償處理,因爲這些消息可能本身就有問題,也有可能和消費邏輯調用的服務有關等,所以需要人工判斷之後再進行處理。

7.4 消費冪等

消費冪等,指的就是一個消息無論被消費多少次,結果都是一樣的。比如不加樂觀鎖更新一個商品金額到100塊,無論更新多少次,結果都是100塊。

導致消息重複消費的情況有兩種.

1.producer傳遞消息到broker中時,broker因爲網絡波動或者producer宕機,導致producer沒有收到broker的響應,producer會重新發送一條消息。

2.broker投遞消息到consumer,consumer消費消息成功,但是ack因爲網絡原因沒有回傳到broker,導致broker重新投遞消息到consumer。

對於一些允許消息重複的場景,可以不必關心消費冪等。但是對於那些不允許消息重複的業務場景來說,可通過業務上的唯一標識來作爲冪等處理的依據或者在代碼層面來做消費的一個冪等

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章