RabbitMQ使用時注意的一些問題

 1、前言數據庫

      上篇RabbitMQ的博文竟然上了推薦,效果很不錯,接下來咱們就來聊聊咱們RabbitMQ的方案,先談方案,代碼等等後面補上,感受不錯給我點點關注,點點👍,原本能早點寫完這篇博文的,因爲工做最近很繁忙稍微推遲一些時間。緩存

 2、方案網絡

      方案從兩方面談:生產者的投遞以及消費端的消費。函數

      生產端設計

      生產端要保障的是消息發出去,RabbitMQ的Borker收到而且返會確認收到,因爲網絡的緣由消息發送Borker的時候可能失敗,另外Borker返回給生產者確認的時候也可能發生閃斷,因此爲了保障100%投遞咱們還須要合理的補償機制。主要提供兩種方案:消息打標和延時隊列,仍是以最經典的下訂單的場景爲例:blog

      消息打標:隊列

      消息打標的意思就是將消息落庫之後,裏面對消息狀態進行記錄,標記爲發送中以及發送成功兩種狀態,而後採用定時輪詢任務的方式去查找消息是否發送成功,具體看下圖:回調函數

      

        接下來咱們詳細介紹一下該流程:it

        1.訂單生成同時落地到訂單表和消息記錄表,這裏的消息記錄表能夠用MongoDB或者ES等方式進行替代;百度

        2.從消息記錄表讀取消息,發送消息到Borker同時更改消息狀態爲發送中;

        3.假設消息接收成功,Borker接收消息成功,並返回確認收到給生產者,這個時候更新消息記錄表消息狀態爲成功;

        4.假設消息接收失敗,可能失敗的地方有兩個處:Borker接收消息和返回消息均可能發生網絡問題或者其餘情況,致使生產者接收不到返回值;

        5.定時任務輪詢,規定時間內沒有發送成功消息再次按照步驟2進行投遞,這個規定時間最多容忍2或者次查詢輪詢同一個條消息,若是依然接收不成功,那麼則設置消息接收失敗,這裏多是交換機或者隊列綁定失敗形成的,須要咱們人工排查;

        延遲隊列:

        使用延遲隊列對消息的延遲投遞,經過回調函數作二次檢查確認消息投遞成功;延遲隊列是針對消息來講,是指當消息發送出去之後不想當即被消費,而是等待特定的時間後,消費者才進行消費,好比咱們常見的支付付款,30分鐘內必須付款成功,不然就異常,這裏是延遲隊列的經典場景;RabbitMQ來講自己是不支持延遲隊列的,可是能夠經過死信隊列和過時時間來實現延遲隊列,簡單解釋下就是生產隊發佈消息到正常隊列,設置過時時間,綁定死信交換機,消費端直接消費死信隊列,這樣就完成延遲隊列的實現;經過延時隊列去實現消息100%可靠投遞的化,會涉及到消費者消費的問題,相對比較複雜;

       

       接下來咱們詳細介紹經過延遲隊列實現消息100%可靠投遞的流程:

       1.當訂單落庫之後,生產者發送消息給Borker,而且發送延時消息,該消息是用來作二次檢查確認的;

       2.消費者(2)消費成功之後,將消費成功的消息體回發到Borker中(3);

       3.回調服務(4)消費Boker中消費者消費成功的消息體而且入庫;

       4.當延時隊列(5)中存在消息時候作檢查數據庫是否存在消息,若是存在着消息消費成功,若是不存在則消息消費失敗,同時再次調用生產者發送消息;

       以上就是我前面提到過的兩種方案,咱們公司如今仍是再用第一種 ,對於第二種主要是爲了提高系統的吞吐量,減小一次入庫;其實合適思想就是經過補償,來完成消息100%投遞,這裏面就存在一個問題,同一條消息可能會被投遞屢次,可能照成消費端屢次消費同一條消息,因此這個時候咱們就要考慮客戶端冪等性的設計;另外消費端消費的時候,消息的順序是得不到保障的,若是有業務之間相互依賴就須要考慮消息順序不一致時候處理。

       消費端

       消費端消費須要注意得地方就是上面提到得兩種狀況:冪等性以及消息的順序問,接下來咱們也來聊一聊消費端的設計問題。

       冪等性

       冪等性這個也是咱們Web端設計時候要考慮的問題之一,冪等性就是屢次提交與一次提交看到的結果是相同的,這裏解釋的有點簡單,感興趣的本身百度下深刻了解下;這裏咱們來聊聊咱們消費端怎麼來設計實現冪等;

       1.惟一id+業務規則,利用數據庫主鍵去重,咱們如今就是經過惟一id去重,業務規則具體能夠根據大家的使用場景去決定你是否須要加上這個條件;

       2.經過Redis去實現冪等,經過Redis緩存去判斷該消息是否消費過,可是這個時候咱們要考慮Redis與數據庫怎麼要保障原子性的問題;

       業務依賴(順序性)

       這個問題其實我不太介意設計這麼複雜,可是要是真是存在這樣的場景,那也聊一聊個人一些想法:

       1.保障順序消費的消息都須要在同一個隊列中,保障順序消費的消息的Id是一致的,而且消費者只能有一個;

       2.增長消息體屬性:順序消費的標記用來區分誰先消費;

       3.當消費端消費之後,若是是消費順序正確,那麼落庫,若是消息順序不正確,則先落庫消息,而且發送延時消息;

       4.當收到延時隊消息的時候,而後根據消息id查詢數據庫,進行數據處理,若是仍是順序不對則再次發送延時消息;

       爲何這麼設計?其實不這麼設計也是能夠,好比咱們消息順序不對的時候,直接投入延時隊列,這種不能區分到底誰先被消費,只能靠隨機去嘗試,極端狀況下可能不少次都沒法保證順序是一致,因此我增長順序標記的想法,爲何要保證到同一個隊列和只有一個消費者,這是爲了保證順序性,當多個隊列,多個消費者的時候順序性更難保證。

       以上都是我本身的一些想法,若是發現不對,請指正謝謝!

 3、結束

       最近一段時間比較忙,代碼部分我想作一些封裝,暫時沒時間寫,等等穩定之後補充上,你們在稍微等等,接下來還會介紹一些消息存儲和鏡像隊列方面的知識,歡迎你們加羣438836709!歡迎你們關注我!

       

相關文章
相關標籤/搜索