RabbitMQ就是 AMQP 協議的 Erlang 的實現(當然 RabbitMQ 還支持 STOMP2、 MQTT3 等協議 ) AMQP 的模型架構 和 RabbitMQ 的模型架構是一樣的,生產者將消息發送給交換器,交換器和隊列綁定 。RabbitMQ 中的交換器、交換器類型、隊列、綁定、路由鍵等都是遵循的 AMQP 協議中相應的概念。
采用AMQP高級消息隊列協議的一種消息隊列技術,最大的特點就是消費并不需要確保提供方存在,實現了服務之間的高度解耦。
1.在分布式系統下具備異步,削峰,負載均衡等一系列高級功能;
2.擁有持久化的機制,進程消息,隊列中的信息也可以保存下來。
3.實現消費者和生產者之間的解耦。
4.對于高并發場景下,利用消息隊列可以使得同步訪問變為串行訪問達到一定量的限,利于數據庫的操作。
5.可以使用消息隊列達到異步下單的效果,排隊中,后臺進行邏輯下單。
1.服務間異步通信
2.順序消費
3.定時任務
4.請求削峰
Broker:簡單來說就是消息隊列服務器實體
Exchange:消息交換機,它指定消息按什么規則,路由到哪個隊列
Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列
Binding:綁定,它的作用就是把exchange和queue按照路由規則綁定起來
Routing Key: 路由關鍵字,exchange根據這個關鍵字進行消息投遞
VHost:vhost可以理解為虛擬broker ,即mini-RabbitMQ server。其內部均含有獨立的queue、exchange和binding等,但最最重要的是,其擁有獨立的權限系統,可以做到vhost范圍的用戶控制。當然,從RabbitMQ的全局角度,vhost可以作為不同權限隔離的手段(一個典型的例子就是不同的應用可以跑在不同的 vhost 中)。
Producer: 消息生產者,就是投遞消息的程序
Consumer:消息消費者,就是接受消息的程序
Channel:消息通道,在客戶端的每個連接里,可建立多個channel,每個channel代表一個會話任務由Exchange、Queue、RoutingKey三個才能決定一個從Exchange到Queue的唯一的線路。
消息的發送方有個確認模式,具體的流程如下:
1.將信道設置成confirm模式(發送方確認模式),則所有在信道上發布的消息都會被指派一個唯一的ID。
2.一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一 ID)。
3.如果 RabbitMQ發生內部錯誤從而導致消息丟失,會發送一條nack(notacknowledged,未確認)消息。發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。
消息的接收方消息確認機制,具體的流程如下:
消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。這里并沒有用到超時機制,RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer足夠長的時間來處理消息。保證數據的最終一致性;
如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ會認為消息沒有被分發,然后重新分發給下一個訂閱的消費者。
在消息生產時,RabbitMQ內部針對每條生產者發送的消息生成一個inner-msg-id,作為去重的依據(消息投遞失敗并重傳),避免重復的消息進入隊列;
在消息消費時,要求消息體中必須要有一個 bizId(對于同一業務全局唯一,如支付ID、訂單ID、帖子ID 等)作為去重的依據,避免同一條消息被重復消費。
消息不丟失需要堆消息進行持久化。
確保持久性消息能從服務器重啟中恢復的方式是,將它們寫入磁盤上的一個持久化日志文件,當發布一條持久性消息到持久交換器上時,Rabbit會在消息提交到日志文件后才發送響應。一旦消費者從持久隊列中消費了一條持久化消息,RabbitMQ會在持久化日志中把這條消息標記為等待垃圾收集。如果持久化消息在被消費之前RabbitMQ重啟,那么Rabbit會自動重建交換器和隊列(以及綁定),并重新發布持久化日志文件中的消息到合適的隊列。
由于TCP連接的創建和銷毀開銷較大,且并發數受系統資源限制,會造成性能瓶頸。RabbitMQ使用信道的方式來傳輸數據。信道是建立在真實的TCP連接內的虛擬連接,且每條TCP連接上的信道數量沒有限制。
若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息并進行確認)。
主要有3種:
1.fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上
2.direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列
3.topic:可以使來自不同源頭的消息能夠到達同一個隊列。 使用topic交換器時,可以使用通配符
1.簡單模式,用的默認交換機,1個生產者,1個消費者,一個消息只能被一個消費者消息
2.工作模,多個消費者監聽同一個隊列,如果任務數據比較多,可以多幾個消費者,可以加快消費的速度
3.訂閱發布模式,引入了交換機的類型fanout,廣播模式 ,每個消費者單獨監聽自己的對列都可以取消費自己隊列的消息。
4.routing,是direct的的交換機類型,指定路由
5.topic,是topic的交換機類型,比路由多了通配符的更加的靈活
完成RabbitMQ消息路由的核心組件是 Exchange。而消息的路由是由Exchange類型 和 Binding 來決定的。Binding 表示建立 Queue 和 Exchange 之間的綁定關系,每一個綁定關系會存在一個 BindingKey。通過這種方式相當于在 Exchange 中建立了一個路由關系表。生產者發送消息的時候,需要聲明一個 RoutingKey(路由鍵),Exchange 拿到RoutingKey 之后,根據 RoutingKey 和路由表里面的 BindingKey 進行匹配,而匹配的規則是通過 Exchange類型來決定的。在 RabbitMQ 中,默認有四種類型的 Exchange:Direct ,Fanout、Topic和Header。
Direct,叫直連,也就是完整匹配方式,需要Routing Key 和 Binding Key 完全一致,相當于點對點的發送。
Topic: 叫主題,這種方式是通過設置通配符來動態匹配,相當于正則。就是用Routing Key 去匹配Binging Key。BingingKey支持兩個通配符。
Fanout:叫廣播,這種方式不需要設置Routing Key,而是把消息廣播給綁定到當前 Exchange 上的所有隊列上。
1)拆分多個queue(消息隊列),每個queue(消息隊列) 一個consumer(消費者),就是多一些queue(消息隊列)而已,這種方式會比較麻煩;
2)一個queue (消息隊列)但是對應一個consumer(消費者),然后這個consumer(消費者)內部用內存隊列做排隊,然后分發給底層不同的worker來處理。
首先,必然導致性能的下降,因為寫磁盤比寫RAM慢的多,message的吞吐量可能有10倍的差距。
其次,message的持久化機制用在RabbitMQ的內置cluster方案時會出現“坑爹”問題。矛盾點在于,若message設置了persistent屬性,但queue未設置durable屬性,那么當該queue的owner node出現異常后,在未重建該queue前,發往該queue 的message將被 blackholed;若 message 設置了 persistent屬性,同時queue也設置了durable屬性,那么當queue的owner node異常且無法重啟的情況下,則該queue無法在其他node上重建,只能等待其owner node重啟后,才能恢復該 queue的使用,而在這段時間內發送給該queue的message將被 blackholed 。
所以,是否要對message進行持久化,需要綜合考慮性能需要,以及可能遇到的問題。若想達到100,000 條/秒以上的消息吞吐量(單RabbitMQ服務器),則要么使用其他的方式來確保message的可靠delivery ,要么使用非常快速的存儲系統以支持全持久化(例如使用SSD)。
另外一種處理原則是:僅對關鍵消息作持久化處理(根據業務重要程度),且應該保證關鍵消息的量不會導致性能瓶頸。
RabbitMQ有三種模式:單機模式、普通集群模式、鏡像集群模式。
單機模式就是Demo級別的,一般就是你本地啟動了玩玩兒的?,沒人生產用單機模式
普通集群模式就是在多臺機器上啟動多個RabbitMQ實例,每個機器啟動一個。你創建的queue,只會放在一個RabbitMQ實例上,但是每個實例都同步queue的元數據。你消費的時候,實際上如果連接到了另外一個實例,那么那個實例會從queue所在實例上拉取數據過來。這方案主要是提高吞吐量的,就是說讓集群中多個節點來服務某個queue的讀寫操作。
鏡像集群模式才是所謂的RabbitMQ的高可用模式。這種模式下,每個RabbitMQ節點都有這個queue的一個完整鏡像,包含queue的全部數據的意思。然后每次你寫消息到queue的時候,都會自動把消息同步到多個實例的queue上。RabbitMQ有很好的管理控制臺,就是在后臺新增一個策略,這個策略是鏡像集群模式的策略,指定的時候是可以要求數據同步到所有節點的,也可以要求同步到指定數量的節點,再次創建queue的時候,應用這個策略,就會自動將數據同步到其他的節點上去了。這樣的好處在于,你任何一個機器宕機了,沒事兒,其它機器(節點)還包含了這個queue的完整數據,別的consumer都可以到其它節點上去消費數據。壞處在于,第一,這個性能開銷也太大了吧,消息需要同步到所有機器上,導致網絡帶寬壓力和消耗很重!RabbitMQ一個queue的數據都是放在一個節點里的,鏡像集群下,也是每個節點都放這個queue的完整數據。