簡單聊一下RabbitMQ

RabbitMQ憑藉着其異步解耦的兩大核心特性在分佈式系統應用中大放異彩。雖然在平時工作中經常用到,但是卻很少去深入研究。這兩天看了一下《RabbitMQ實戰》,總結了平時不太注意的幾個點。

1、Erlang

RabbitMQ是用Erlang語言開發的,聽說Erlang在處理通信和併發時很是擅長。

2、AMQP

RabbitMQ是一個實現了AMQP(Advanced Message Queuing Protocol,即高級消息隊列協議)標準的代理服務器。

AMQP協議模型

3、信道

應用程序和RabbitMQ之間創建一條TCP連接,才能消費或者發佈消息。信道是建立在“真實的”TCP連接內的虛擬連接。AMQP命令都是通過信道發送出去的。在一條TCP連接上創建多少條信道是沒有限制的。

4、虛擬主機

vhost,相當於一個mini版的RabbitMQ服務器,擁有自己的隊列、交換機和綁定。可以給用戶分配每個vhost的不同權限。虛擬主機配合用戶權限一般用於隔離系統、模塊或者環境等。

5、隊列

(1)消費者通過以下兩種方式從特定的隊列中接收消息

  • basic.consume命令:消費後自動接收下一條消息。信道置爲接收模式直到取消訂閱。推薦用法。
  • basic.get命令:每次調用接收下一條消息。相當於訂閱->獲得消息->取消訂閱,影響性能。

(2)如果至少有一個消費者訂閱了隊列的話,消息會立即發送給這些訂閱的消費者。如果消息到達了無人訂閱的隊列,消息會在隊列中等待,一旦有消費者訂閱到該隊列,那麼隊列上的消息就會發送給消費者。

(3)當隊列擁有多個消費者時,隊列收到的消息將以循環(round-robin)的方式發送給消費者。每條消息只會發送給一個訂閱的消費者。

(4)消費者接收到的每一條消息都必須進行確認,這樣RabbitMQ才能安全地把消息從隊列中刪除。可以通過basic.ack命令顯式地向RabbitMQ發送一個確認。或者將auto_ack參數設置爲true,這樣一旦消費者接收消息,RabbitMQ會自動視其確認了消息。

(5)如果消費者收到一條消息,然後確認之前從RabbitMQ斷開連接(或者從隊列上取消訂閱),RabbitMQ會認爲這條消息沒有分發,然後重新分發給下一個訂閱的消費者。這樣做可以保證你的應用程序崩潰了,消息也會被髮送給另一個消費者進行處理。另一方面,如果應用程序有bug而忘記確認消息的話,RabbitMQ將不會給該消費者發送更多消息了。

(6)在收到消息後如果想要明確拒絕而不是確認的話,有兩種選擇

  • 把消費者從RabbitMQ服務器斷開連接,這樣RabbitMQ就會自動重新把消息入隊併發送給另一個消費者。不推薦。
  • 如果RabbitMQ是2.0.0及以上的版本,那就使用basic.reject命令:如果reject命令的requeue參數設置爲true,RabbitMQ會將消息重新發送給下一個訂閱的消費者;如果設置爲false的話RabbitMQ會將消息從隊列中移除,而不會把它發送給新的消費者。

(7)新的版本支持”死信“(dead letter)隊列,用來存放那些被拒絕而不重入隊列的消息。如果應用程序想自動從死信隊列中獲益的話,需要使用reject命令並將requeue參數設置成false。

6、交換器

服務器會根據Routing key將消息從交換器路由到隊列。四種交換機類型

  • headers:允許匹配消息的header而非路由鍵,除此之外和direct完全一致但是性能差很多,所以不太實用。
  • direct:如果路由鍵匹配的話,消息就被投遞到對應的隊列。RabbitMQ有一個空白字符串名稱的默認交換器,當聲明一個隊列時,它會自動綁定到默認的交換器,並以隊列名稱作爲路由鍵。
  • fanout:這種類型的交換器會將收到的消息廣播到綁定的隊列上。這允許你對單條消息做不同方式的處理。
  • topic:跟direct很像,不過它的路由規則可以使用通配符。

7、持久化

每個隊列和交換器都有durable屬性(默認爲false),它決定了RabbitMQ是否需要在崩潰或者重啓之後重新創建隊列或者交換器。

消息想要持久化,必須滿足三個條件

  • 把它的投遞模式選項設置爲2(持久)
  • 發送到持久化的交換器
  • 到達持久化的隊列

代價:寫入磁盤的持久化日誌文件,性能影響很大。

8、事務

在AMQP中,在把信道設置成事務模式後,你通過信道發送那些想要確認的消息,之後還有多個其它AMQP命令。這些命令是執行還是忽略,取決於第一條消息發送是否成功。使用事務會降低消息吞吐量,也會使生產者應用程序產生同步。發送方確認模式可以保證消息投遞:它是異步的,當確認消息最終收到的時候,生產者應用的回調方法就會被觸發來處理。

9、其它

(1)當消費者處理消息失敗的時候怎麼辦?我們系統目前採用的一種方式是:創建一個消息補償隊列和消息失敗記錄表,當消費失敗時,將消息內容、業務方法、失敗次數丟到補償隊列中,然後該隊列的消費者根據消息內容和業務方法通過反射調用處理,如果還是失敗就繼續丟回補償隊列。如果達到了指定的失敗次數,則插入失敗記錄表,並且告警到企業微信提示人工檢查處理。

(2)在分佈式系統中,不可避免地會出現分佈式事務,如果保證強一致性難免也會帶來複雜性和影響吞吐量,這個時候往往會保證最終一致性即可。使用MQ保證消息投遞的最終一致性也成爲了解決分佈式事務的常用方案。

未完,待續...

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