使用RabbitMQ有什么好處?
- 應用解耦(系統拆分)
- 異步處理(預約掛號業務處理成功后,異步發送短信、推送消息、日志記錄等)
- 消息分發
- 流量削峰
- 消息緩沖
消息基於什么傳輸?
由於TCP連接的創建和銷毀開銷較大,且並發數受系統資源限制,會造成性能瓶頸。RabbitMQ使用信道的方式來傳輸數據。信道是建立在真實的TCP連接內的虛擬連接,且每條TCP連接上的信道數量沒有限制。
消息怎么路由?
從概念上來說,消息路由必須有三部分:交換器、路由、綁定。生產者把消息發布到交換器上;綁定決定了消息如何從路由器路由到特定的隊列;消息最終到達隊列,並被消費者接收。常用的交換器主要分為一下三種:
- direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列
- fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上
- topic:可以使來自不同源頭的消息能夠到達同一個隊列。 使用topic交換器時,可以使用通配符,比如:“*” 匹配特定位置的任意文本, “.” 把路由鍵分為了幾部分,“#” 匹配所有規則等。特別注意:發往topic交換器的消息不能隨意的設置選擇鍵(routing_key),必須是由"."隔開的一系列的標識符組成。
如何做到信息的可靠性?確保消息正確地發送至RabbitMQ?確保消息接受方消費了消息?休息不丟失不重復?
采用事務或發送方確認模式保證消息發送到rabbitmq。 發送方確認模式:將信道設置成confirm模式(發送方確認模式),則所有在信道上發布的消息都會被指派一個唯一的ID。一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一ID)。如果RabbitMQ發生內部錯誤從而導致消息丟失,會發送一條nack(not acknowledged,未確認)消息。發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。
接收方消息確認機制來確保消息被消費:消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer足夠長的時間來處理消息。消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ會認為消息沒有被分發,然后重新分發給下一個訂閱的消費者。(可能存在消息重復消費的隱患,需要根據bizId去重)
在消息生產時,MQ內部針對每條生產者發送的消息生成一個inner-msg-id,作為去重和冪等的依據(消息投遞失敗並重傳),避免重復的消息進入隊列;在消息消費時,要求消息體中必須要有一個bizId(對於同一業務全局唯一,如支付ID、訂單ID、帖子ID等)作為去重和冪等的依據,避免同一條消息被重復消費。
vhost 是什么?起什么作用?
答:vhost 可以理解為虛擬 broker ,即 mini-RabbitMQ server。其內部均含有獨立的 queue、exchange 和 binding 等,但最最重要的是,其擁有獨立的權限系統,可以做到 vhost 范圍的用戶控制。當然,從 RabbitMQ 的全局角度,vhost 可以作為不同權限隔離的手段(一個典型的例子就是不同的應用可以跑在不同的 vhost 中)。為什么使用集群?
內建集群作為RabbitMQ最優秀的功能之一,它的作用有兩個:
- 允許消費者和生產者在Rabbit節點崩潰的情況下繼續運行;
- 通過增加節點來擴展Rabbit處理更多的消息,承載更多的業務量;
RabbitMQ的集群是由多個節點組成的,但我們發現不是每個節點都有所有隊列的完全拷貝。
RabbitMQ節點不完全拷貝特性
為什么默認情況下RabbitMQ不將所有隊列內容和狀態復制到所有節點?
有兩個原因:
- 存儲空間——如果每個節點都擁有所有隊列的完全拷貝,這樣新增節點不但沒有新增存儲空間,反而增加了更多的冗余數據。
- 性能——如果消息的發布需安全拷貝到每一個集群節點,那么新增節點對網絡和磁盤負載都會有增加,這樣違背了建立集群的初衷,新增節點並沒有提升處理消息的能力,最多是保持和單節點相同的性能甚至是更糟。
所以其他非所有者節點只知道隊列的元數據,和指向該隊列節點的指針。根據節點不無安全拷貝的特性,當集群節點崩潰時,該節點隊列和關聯的綁定就都丟失了,附加在該隊列的消費者丟失了其訂閱的信息,那么怎么處理這個問題呢?
這個問題要分為兩種情況:
- 消息已經進行了持久化,那么當節點恢復,消息也恢復了;
- 消息未持久化,可以使用下文要介紹的雙活冗余隊列,鏡像隊列保證消息的可靠性;
集群節點類型
節點的存儲類型分為兩種:
- 磁盤節點
- 內存節點
磁盤節點就是配置信息和元信息存儲在磁盤上,內次節點把這些信息存儲在內存中,當然內次節點的性能是大大超越磁盤節點的。
單節點系統必須是磁盤節點,否則每次你重啟RabbitMQ之后所有的系統配置信息都會丟失。
RabbitMQ要求集群中至少有一個磁盤節點,當節點加入和離開集群時,必須通知磁盤節點。
特殊異常:集群中唯一的磁盤節點崩潰了
如果集群中的唯一一個磁盤節點,結果這個磁盤節點還崩潰了,那會發生什么情況?
如果唯一磁盤的磁盤節點崩潰了,不能進行如下操作:
- 不能創建隊列
- 不能創建交換器
- 不能創建綁定
- 不能添加用戶
- 不能更改權限
- 不能添加和刪除集群幾點
總結:如果唯一磁盤的磁盤節點崩潰,集群是可以保持運行的,但你不能更改任何東西。
解決方案:在集群中設置兩個磁盤節點,只要一個可以,你就能正常操作。