rabbitmq
架構圖
RabbitMQ 中的 broker 是指什么?cluster 又是指什么
- broker 是指一個或多個 erlang node 的邏輯分組,且 node 上運行着 RabbitMQ 應用程序。cluster 是在 broker 的基礎之上,增加了 node 之間共享元數據的約束
概念
-
Broker:消息隊列服務器實體
-
exchange:消息交換機,指定消息規則,處理消息和隊列之間的關系
- Exchange是屬於Vhost的。同一個Vhost不能有重復的Exchange名稱。
- Exchange的綁定功能,可以綁定queue,也可以綁定Exchange
-
queue:隊列載體,消息投入隊列中
-
binding:綁定,把exchange和queue按照路由規則綁定起來
-
Routing Key:路由關鍵字。exchange根據這個進行消息投遞
-
vhost:虛擬消息服務器,每個RabbitMQ服務器都能夠創建虛擬消息服務器。
- Vhost之間相互完全隔離,不同Vhost之間無法共享Exchange和Queue。因此Vhost之間數據無法共享和分享。
- RabbitMQ的Vhost主要是用來划分不同業務模塊。不同業務模塊之間沒有信息交互。
- vhost 可以理解為虛擬 broker ,即 mini-RabbitMQ server。其內部均含有獨立的 queue、exchange 和 binding 等,但最最重要的是,其擁有獨立的權限系統,可以做到 vhost 范圍的用戶控制。當然,從 RabbitMQ 的全局角度,vhost 可以作為不同權限隔離的手段
-
producer:生產者,投遞消息的程序
-
consumer:消費者,接受消息的程序
-
channel:信道(重要概念),打開信道才能進行通信,一個channel代碼一個會話任務
- channel 是真實 TCP 連接之上的虛擬連接
消息基於什么傳輸
- 由於TCP連接的創建和銷毀開銷較大,且並發數受系統資源限制,會造成性能瓶頸。RabbitMQ使用信道的方式來傳輸數據。channel是建立在真實的TCP連接內的虛擬連接,且每條TCP連接上的信道數量沒有限制
“dead letter”queue 的用途?
- 當消息被 RabbitMQ server 投遞到 consumer 后,但 consumer 卻通過 Basic.Reject 進行了拒絕時(同時設置 requeue=false),那么該消息會被放入“dead letter”queue 中。該 queue 可用於排查 message 被 reject 或 undeliver 的原因。
為什么說保證 message 被可靠持久化的條件是 queue 和 exchange 具有 durable 屬性,同時 message 具有 persistent 屬性才行
- binding 關系可以表示為 exchange – binding – queue 。從文檔中我們知道,若要求投遞的 message 能夠不丟失,要求 message 本身設置 persistent 屬性,要求 exchange 和 queue 都設置 durable 屬性。其實這問題可以這么想,若 exchange 或 queue 未設置 durable 屬性,則在其 crash 之后就會無法恢復,那么即使 message 設置了 persistent 屬性,仍然存在 message 雖然能恢復但卻無處容身的問題;同理,若 message 本身未設置 persistent 屬性,則 message 的持久化更無從談起。
Exchange Type
- 過程
- 消息發布到交換器時,消息將擁有一個路由鍵(routing key),在消息創建時設定。
- 通過隊列路由鍵,可以把隊列綁定到交換器上。
- 消息到達交換器后,RabbitMQ會將消息的路由鍵與隊列的路由鍵進行匹配
- fanout
- fanout類型的Exchange路由規則非常簡單,它會把所有發送到該Exchange的消息路由到所有與它綁定的Queue中。
- direct
- direct類型的Exchange路由規則也很簡單,它會把消息路由到那些binding key與routing key完全匹配的Queue中
- topic
- topic這個規則就是模糊匹配,可以通過通配符滿足一部分規則就可以傳送。
使用RabbitMQ有什么好處
應用解耦(系統拆分)
異步處理(預約掛號業務處理成功后,異步發送短信、推送消息、日志記錄等)
消息分發
流量削峰
消息緩沖
監控
JMS協議
- JMS(Java Messaging Service)是Java平台上有關面向消息中間件的技術規范,它便於消息系統中的Java應用程序進行消息交換,並且通過提供標准的產生、發送、接收消息的接口簡化企業應用的開發。
- JMS本身只定義了一系列的接口規范,是一種與廠商無關的 API,用來訪問消息收發系統。它類似於 JDBC(Java Database Connectivity):
- 消息是 JMS 中的一種類型對象,由兩部分組成:報頭和消息主體。報頭由路由信息以及有關該消息的元數據組成。消息主體則攜帶着應用程序的數據或有效負載。根據有效負載 的類型來划分,可以將消息分為幾種類型,它們分別攜帶:簡單文本 (TextMessage)、可序列化的對象 (ObjectMessage)、屬性集合 (MapMessage)、字節流 (BytesMessage)、原始值流 (StreamMessage),還有無有效負載的消息 (Message)。
訂閱模式publish/subscribe
一個生產者 多個消費者
- 每個消費者都有自己的隊列
生產者沒有直接把消息發送給隊列,而是先發送給交換機exchange
每個隊列都要綁定到交換機上
生產者發送的消息是經過交換機的,然后到達隊列,就能實現一個消息被多個消費者消費 - 若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者
Confirm機制:
- 使用事務固然可以保證只有提交的事務,才會被服務器執行。但是這樣同時也將客戶端與消息服務器同步起來,這背離了消息隊列解耦的本質。
- Rabbit MQ提供了一個更加輕量級的機制來保證生產者可以感知服務器消息是否已被路由到正確的隊列中——Confirm。如果設置channel為confirm狀態,則通過該channel發送的消息都會被分配一個唯一的ID,然后一旦該消息被正確的路由到匹配的隊列中后,服務器會返回給生產者一個Confirm,該Confirm包含該消息的ID,這樣生產者就會知道該消息已被正確分發。對於持久化消息,只有該消息被持久化后,才會返回Confirm。Confirm機制的最大優點在於異步,生產者在發送消息以后,即可繼續執行其他任務。而服務器返回Confirm后,會觸發生產者的回調函數,生產者在回調函數中處理Confirm信息。如果消息服務器發生異常,導致該消息丟失,會返回給生產者一個nack,表示消息已經丟失,這樣生產者就可以通過重發消息,保證消息不丟失。Confirm機制在性能上要比事務優越很多。但是Confirm機制,無法進行回滾,就是一旦服務器崩潰,生產者無法得到Confirm信息,生產者其實本身也不知道該消息吃否已經被持久化,只有繼續重發來保證消息不丟失,但是如果原先已經持久化的消息,並不會被回滾,這樣隊列中就會存在兩條相同的消息,系統需要支持去重。
事務
- 對事務的支持是AMQP協議的一個重要特性。假設當生產者將一個持久化消息發送給服務器時,因為consume命令本身沒有任何Response返回,所以即使服務器崩潰,沒有持久化該消息,生產者也無法獲知該消息已經丟失。如果此時使用事務,即通過txSelect()開啟一個事務,然后發送消息給服務器,然后通過txCommit()提交該事務,即可以保證,如果txCommit()提交了,則該消息一定會持久化,如果txCommit()還未提交即服務器崩潰,則該消息不會服務器就收。當然Rabbit MQ也提供了txRollback()命令用於回滾某一個事務。
消息恢復
- consumer從durable queue中取回一條消息之后並發回了ACK消息,RabbitMQ就會將其標記,方便后續垃圾回收.如果一條持久化的消息沒有被consumer取走,RabbitMQ重啟之后會自動重建exchange和queue(以及bingding關系),消息通過持久化日志重建再次進入對應的queues,exchanges.
持久化
- 消息的持久化需要在消息投遞的時候設置delivery mode值為2.由於消息實際存儲於queue之中,"皮之不存毛將焉附"邏輯上,消息持久化同時要求exchange和queue也是持久化的.這是消息持久化必須滿足的三個條件.
- 持久化的代價就是性能損失,磁盤IO遠遠慢於RAM(使用SSD會顯著提高消息持久化的性能) , 持久化會大大降低RabbitMQ每秒可處理的消息.兩者的性能差距可能在10倍以上.
多個Consumer訂閱同一個隊列
- 如果一個rabbit queue有多個consumer,具體到隊列中的某條消息只會發送到其中的一個Consumer.
RabbitMQ的消息狀態
- Ready:等待消費狀態。
- Unacked:等待被確認狀態,當前消息已經被發送到了客戶端。當客戶端端斷開后,如果這條消息沒有被確認,這條消息重新進入Ready中。
RabbitMQ的高可用性
-
rabbitmq有三種模式:單機模式,普通集群模式,鏡像集群模式
-
普通集群模式
- 意思就是在多台機器上啟動多個rabbitmq實例,每個機器啟動一個。但是你創建的queue,只會放在一個rabbtimq實例上,但是每個實例都同步queue的元數據。
-
rabbitmq有三種模式:單機模式,普通集群模式,
- 這種模式,才是所謂的rabbitmq的高可用模式,跟普通集群模式不一樣的是,你創建的queue,無論元數據還是queue里的消息都會存在於多個實例上,然后每次你寫消息到queue的時候,都會自動把消息到多個實例的queue里進行消息同步。
- 這樣的話,好處在於,你任何一個機器宕機了,沒事兒,別的機器都可以用。壞處在於,第一,這個性能開銷也太大了吧,消息同步所有機器,導致網絡帶寬壓力和消耗很重!第二,這么玩兒,就沒有擴展性可言了,如果某個queue負載很重,你加機器,新增的機器也包含了這個queue的所有數據,並沒有辦法線性擴展你的queue
- 那么怎么開啟這個鏡像集群模式呢?我這里簡單說一下,避免面試人家問你你不知道,其實很簡單rabbitmq有很好的管理控制台,就是在后台新增一個策略,這個策略是鏡像集群模式的策略,指定的時候可以要求數據同步到所有節點的,也可以要求就同步到指定數量的節點,然后你再次創建queue的時候,應用這個策略,就會自動將數據同步到其他的節點上去了。