[MQ]什麼是消息隊列?

什麼是消息隊列MQ(Message Queue)?

  • 消息(Message):傳輸的數據。

  • 隊列(Queue):隊列是一種先進先出的數據結構。

  • 消息隊列從字面的含義來看就是一個存放消息的容器。

  • 消息隊列可以簡單理解爲:把要傳輸的數據放在隊列中。

  • 把數據放到消息隊列叫做生產者

  • 從消息隊列裏邊取數據叫做消費者

一般來說,消息隊列是一種異步的服務間通信方式,是分佈式系統中重要的組件,主要解決應用耦合,異步消息,流量削鋒等問題,實現高性能,高可用,可伸縮和最終一致性架構。使用較多的消息隊列有RocketMQ、RabbitMQ、Kafka等。

消息隊列使用場景

爲什麼要用消息隊列,也就是在問:用了消息隊列有什麼好處。
消息隊列在實際應用中包括如下三個場景:解耦,異步,削峯

  1. 應用耦合:多應用間通過消息隊列對同一消息進行處理,避免調用接口失敗導致整個過程失敗;
    在這裏插入圖片描述
  2. 異步處理:多應用對消息隊列中同一消息進行處理,應用間併發處理消息,相比串行處理,減少處理時間
    在這裏插入圖片描述
  3. 限流削峯:廣泛應用於秒殺或搶購活動中,避免流量過大導致應用系統掛掉的情況
    在這裏插入圖片描述

消息隊列要面對的問題?

消費者怎麼得到消息隊列的數據?

消費者怎麼從消息隊列裏邊得到數據?有兩種辦法:

  • 生產者將數據放到消息隊列中,消息隊列有數據了,主動叫消費者去拿(俗稱push)
  • 消費者不斷去輪訓消息隊列,看看有沒有新的數據,如果有就消費(俗稱pull)

消息丟失怎麼辦?(消息的可靠性傳輸)

消息的丟失可能會出現在三個地方:

(1)生產者弄丟數據

生產者將數據發送到RabbitMQ的時候,可能數據就在半路給搞丟了,因爲網絡啥的問題,都有可能。怎麼解決?

①事務:生產者發送數據之前開啓RabbitMQ事務(channel.txSelect),然後發送消息,如果消息沒有成功被RabbitMQ接收到,那麼生產者會收到異常報錯,此時就可以回滾事務(channel.txRollback),然後重試發送消息;如果收到了消息,可以提交事務(channel.txCommit)。但是問題是,RabbitMQ事務機制一搞,基本上吞吐量會下來,因爲太耗性能。

②confirm模式:在生產者那裏設置開啓confirm模式之後,你每次寫的消息都會分配一個唯一的id,然後如果寫入了RabbitMQ中,RabbitMQ會給你回傳一個ack消息,告訴你說這個消息ok了。如果RabbitMQ沒能處理這個消息,會回調你一個nack接口,告訴你這個消息接收失敗,你可以重試。而且你可以結合這個機制自己在內存裏維護每個消息id的狀態,如果超過一定時間還沒接收到這個消息的回調,那麼你可以重發。

所以一般在生產者這塊避免數據丟失,都是用confirm機制的。

(2)MQ弄丟數據

就是RabbitMQ自己弄丟了數據,這個你必須開啓RabbitMQ的持久化,就是消息寫入之後會持久化到磁盤,哪怕是RabbitMQ自己掛了,恢復之後會自動讀取之前存儲的數據,一般數據不會丟。

設置持久化有兩個步驟:

①第一個是創建queue和交換器的時候將其設置爲持久化,這樣就可以保證RabbitMQ持久化相關的元數據,但是不會持久化queue裏的數據;

②第二個是發送消息的時候將消息的deliveryMode設置爲2,就是將消息設置爲持久化的,此時RabbitMQ就會將消息持久化到磁盤上去

必須要同時設置這兩個持久化才行

持久化可以和生產者的confirm結合,當持久化成功後,再ack生產者。如果持久化之前RabbitMQ掛了,生產者沒收到ack,會重發。

(3)消費者弄丟數據

RabbitMQ如果丟失了數據,主要是因爲你消費的時候,剛消費到,還沒處理,結果進程掛了,比如重啓了,那麼就尷尬了,RabbitMQ認爲你都消費了,這數據就丟了。

這個時候得用RabbitMQ提供的ack機制,簡單來說,就是你關閉RabbitMQ自動ack,可以通過一個api來調用就行,然後每次你自己代碼裏確保處理完的時候,再程序裏ack一把。這樣的話,如果你還沒處理完,不就沒有ack?那RabbitMQ就認爲你還沒處理完,這個時候RabbitMQ會把這個消費分配給別的consumer去處理,消息是不會丟的。

消費者順序消費問題

從根本上說,異步消息是不應該有順序依賴的。在MQ上估計是沒法解決。要實現嚴格的順序消息,簡單且可行的辦法就是:保證生產者- MQServer -消費者是一對一對一的關係。

如果有順序依賴的消息,要保證消息有一個hashKey,類似於數據庫表分區的的分區key列。保證對同一個key的消息發送到相同的隊列。A用戶產生的消息(包括創建消息和刪除消息)都按A的hashKey分發到同一個隊列。只需要把強相關的兩條消息基於相同的路由就行了,也就是說經過m1和m2的在路由表裏的路由是一樣的,那自然m1會優先於m2去投遞。而且一個queue只對應一個consumer

消息的重複問題

分爲兩大類情況:1、生產者消息重複發送; 2.MQ向消費者投遞時重複投遞

終極解決辦法:冪等性

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