我們為什么要使用RabbitMQ?


 一、前言

       這篇文章就是講RabbitMQ的好處,你可能要說RocketMQ很好呀,我們主要看上的就是RabbitMQ支持多語言的客戶端,很符合我們公司的現狀,不要我們花費功夫去搞一個客戶端,所以下面請大家不要吐槽,我們就來靜心聽聽RabbitMQ的好;

 二、RabbitMQ

      在消息隊列的一發一收中,我們來看下RabbitMQ怎么讓我們放心使用的?首先我們來看下RabbitMQ發收的過程:

      發消息的過程(生產者):

      1.連接到RabbitMQ Borker,建立一個連接(Connection),開啟一個信道(Channel);

      2.聲明交換機(Exchange);

      3.聲明隊列(Queue);

      4.通過路由鍵(Binding Key)將交換機與路由器綁定;

      5.發送消息(消息包含路由鍵(Routing Key)和交換機等內容)到RabbitMQ Borker;

      6.交換機根據接收到路由鍵去匹配到相應的隊列中,如果找到則放入到對應的隊列中,找不到則退回(這里是根據配置信息來的);

      7.關閉;

      收消息的過程(消費者):

      1.連接到RabbitMQ Borker,建立一個連接,開啟一個信道;

      2.請求接收RabbitMQ Borker中隊列的消息;

      3.等待RabbitMQ Borker回應返回隊列中相應的消息;

      4.消費者接收到消息,返回確認(ack);

      5.RabbitMQ移除隊列中對應的消息;

      6.關閉;

      針對上面的過程我們首先來談下生產者RabbitMQ是如何確保一條消息被投遞到RabbitMQ Borker中的,沒有使用過消息隊列可能聽到這里有點懵,這里簡單說一下,當生產者發送一條消息的時候,可能因為網絡的原因或者RabbitMQ服務器宕機了,這個時候我們就無法知道一條消息是否被成功的投遞到RabbitMQ中,針對這些情況RabbitMQ給我們提供兩種機制來處理這個問題,一種是事務機制,另外一種是消息確認機制。事務機制我想大家都很明白了,RabbitMQ客戶端提供與事務機制相關的方法有三個:channel.txSelect、channel.txCommit以及channel.txRollback。channel.txSelect用於將當前信道設置成事務模式,channel.txCommit用於提交事務,channel.txRollback用於事務回滾。當事務開啟以后,發送消息給RabbitMQ,如果消息提交成功,那么說明RabbitMQ一定收到了消息,否則我們可以通過異常來捕獲,然后通過txRollback回滾,當然這種方式性能不好,事務機制將消息串行化,導致發送一條消息必須等待結果。這種方式不太好,那么我們接下來探討一下消息確認機制,涉及到消息確認機制的相關方法有兩個channel.confirmSelect以及channel.waitForConfirms,首先使用confirmSelect將信道設置成為消息確認模式,當使用消息確認模式的時候,該信道上每發布一條消息都會生成唯一的ID,當消息匹配到相應的隊列以后,就會返回一個確認的ack,這個時候生產者就知道投遞消息成功了,如果RabbitMQ發生宕機或者錯誤以后,會返回nack,則表示投遞失敗,當使用waitForConfirms其實是將異步的模式串行化,我們還可以通過addConfirmLister通過ConfirmListener這個回調接口來處理返回值。RabbitMQ通過這兩種機制保證消息能被正確投遞,生產環境中都是使用批量提交,當然實際生產的時候單純這樣還是不能夠保證消息被正確投遞,比如說生產者發送消息時候網絡斷了一下,就不能保證消息被投遞過,所以下一篇我會使用延時隊列和消息打標的方式來保證消息會被100%投遞到RabbitMQ中,當然也不能說是100%只能說是99.好多個9;

      接下來我們來探討下消費者消費的問題,如果消費者在接受到消息以后,比如出現宕機,那么這條消息也就丟失掉了。RabbitMQ針對這種情況,也提供了消息確認機制。當消費訂閱隊列設置autoAck設置為fals的時候,RabbitMQ通過打標的方式,等收到消息確認的時候將隊列中的消息移除出去,如果設置為true,當發送成功以后就將消息移除。當autoAck為fals的時候,RabbitMQ內部會有兩種消息,一種是等待投遞消息,另外一種是等待確認的消息,如果RabbitMQ一直沒有收到消費者確認的消息,並且消費此消息的消費者斷開,那么RabbitMQ會重新發送該條消息,RabbitMQ重新投遞消息的依據就是消費者的該消息連接斷開。消費端可以通過重試機制保證消息能被正常消費,如果重試還消費不掉,那么還可以利用下死信隊列,通過死信隊列中的內容分析程序中可能存在的異常;提到了死信隊列,我們這里也介紹一下,消息成為死信有3種情況:消費端消息被拒絕,並設置requeue參數為false、消息過期以及隊列達到最大長度,綁定死信隊列的交換機就是死信交換機(DLX),當隊列中有死信的時候,RabbitMQ會自動將消息重新發布到設置DLX上,從而被路由死信隊列中;

     RabbitMQ本身是可以將交換機、隊列以及消息都持久化的,當然是不建議將消息持久化的,成本太高。RabbitMQ支持集群模式,是通過多副本的方式實現集群模式,在RabbitMQ中叫做鏡像隊列,當Master宕機以后會按照下面步驟進行:

     1.與Master相關聯的客戶端會全部斷開;

     2.選舉最老的Savle節點作為Master,如果這個時候所有Salve都沒處於同步狀態,則未同步的消息會被丟失掉;

     3.出於對消息可靠性的考慮,新的Master會重新入隊所有客戶端未確認的消息;

     4.如果客戶端連着slave,並且Basic.Consume消費時指定了x-cancel-on-ha-failover參數,那么客戶端會接收到一個Consumer Cancellation Notification通知。如果未指定x-cancal-on-ha-failover參數,那么消費者就無法感知master宕機,會一直等待下去。

     另外RabbitMQ還支持優先級隊列、多協議、多租戶等等,性能方面的話能滿足我們公司業務,記得好像我們這邊高峰期達到4W-5W/s,最主要的RabbitMQ社區很活躍;

三、結束

     下一篇我會使用Java和C#分別去實現上面生產者和消費者的模式,本文主要參考廝大的書和工作中使用RabbitMQ的經驗, 另外在推薦下廝大的書《RabbitMQ實戰指南》和《深入理解Kafka:核心設計與實踐原理》,講的真的好,歡迎大家加群438836709,歡迎大家關注我!

      

 


免責聲明!

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



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