在異步通信中,消息不會馬上到達接收方,而是被存放到一個容器中,當知足必定的條件以後,消息會被容器發送給接收方,這個容器即消息隊列,而完成這個功能須要雙方和容器以及其中的各個組件遵照統一的約定和規則,
AMQP就是這樣的一種協議,消息發送與接受的雙方遵照這個協議能夠實現異步通信。這個協議約定了消息的格式和工做方式。
生產者(Producer):向Exchange發佈消息的應用。html
消費者(Consumer):從消息隊列queue中消費消息的應用。git
消息隊列(Message Queue):服務器組件,用於保存消息,直到發送給消費者。正則表達式
Queue:消息載體;每一個消息都會被投入到一個或多個隊列。服務器
消息(Message):傳輸的內容。網絡
交換器(exchange):路由組件,接收Producer發送的消息,並根據Routing Key轉發給消息隊列queue。app
Routing Key:路由關鍵字,exchange根據這個Routing Key進行消息投遞到隊列queue。異步
虛擬主機(Virtual Host): 用做不一樣用戶的權限分離;一批交換器,消息隊列和相關對象。虛擬主機是共享相同身份認證和加密環境的獨立服務器域。vhost 能夠理解爲虛擬 broker ,即 mini-RabbitMQ server。其內部均含有獨立的 queue、exchange 和 binding 等,但最最重要的是,其擁有獨立的權限系統,能夠作到 vhost 範圍的用戶控制。固然,從 RabbitMQ 的全局角度,vhost 能夠做爲不一樣權限隔離的手段(一個典型的例子就是不一樣的應用能夠跑在不一樣的權限的 vhost 中) 分佈式
Broker :AMQP的服務端稱爲Broker。 性能
鏈接(Connection):一個網絡鏈接,好比TCP/IP套接字鏈接;應用程序與Rabbit之間創建鏈接的管理器,程序代碼中使用ConnectionFactory(鏈接管理器)。 ui
信道(Channel):消息通道,在客戶端的每一個Connection鏈接裏,可創建多個channel,每一個channel表明一個會話任務;多路複用鏈接中的一條獨立的雙向數據流通道,爲會話提供物理傳輸介質。
綁定器(Binding):把exchange和queue按照路由規則綁定起來。
生產者在發送消息時,都須要指定一個RoutingKey和Exchange,Exchange在接到該RoutingKey之後,會判斷該ExchangeType,而後轉發到對應的Queue中;
生產者發消息不須要指定Queue,消費者能夠指定Queue綁定到某個RoutingKey和某個Exchange,也能夠不指定Queue,就只根據某個Exchange和某個RoutingKey接受到消息。
Exchange 將消息發送到哪個queue是由exchange type 和 Binding綁定規則決定的,目前經常使用的有3種exchange,Direct exchange, Fanout exchange, Topic exchange :
1. Direct exchange 直接轉發路由,其實現原理是會將消息中的RoutingKey與該Exchange關聯的全部Binding中的BindingKey進行比較,若是相等,則發送到該Binding對應的Queue中。
2. Fanout exchange 複製分發路由,該路由不須要RoutingKey,會將消息發送給全部與該 Exchange 定義過Binding的全部Queues中去,實際上是一種廣播行爲。
3. topic exchange 通配路由,是direct exchange的通配符模式,消息中的RoutingKey能夠寫成通配的模式,exchange支持「#」和「*」 的通配。收到消息後,將消息轉發給全部符合匹配正則表達式的Queue。
TopicExchange的匹配符號:
#:匹配多個詞
*: 匹配一個詞
須要注意的一點只有queue具備保存消息的功能,exchange不能保存消息。
RabbitMQ中一個核心的原則是,消息不能直接投遞到Queue中。Producer只能將本身的消息投遞到Exchange中,由Exchange按照路由規則將消息投遞到對應的Queue中。
在Consumer中,聲明本身對哪一個Exchange感興趣,並將本身的Queue綁定到本身感興趣的路由關鍵字上,創建相應的映射關係;第二,在Producer中,將消息投遞一個Exchange中,並指明它的路由關鍵字。
(1)創建鏈接Connection。由producer和consumer分別鏈接到broker的物理節點上。
(2)創建消息Channel。Channel是創建在Connection之上的,一個Connection能夠創建多個Channel;producer鏈接Virtual Host 創建Channel,Consumer鏈接到相應的queue上創建Channel。
(3)發送消息。由Producer發送消息到Broker中的exchange中。
(4)路由轉發。exchange收到消息後,根據必定的路由策略routing key,將消息轉發到相應的queue中去。
(5)消息接收。Consumer會監聽相應的queue,一旦queue中有能夠消費的消息,queue就將消息發送給Consumer端。
(6)消息確認。當Consumer完成某一條消息的處理以後,須要發送一條ACK消息給對應的Queue。Queue收到ACK信息後,纔會認爲消息處理成功,並將消息從Queue中移除;若是在對應的Channel斷開後,Queue沒有收到這條消息的ACK信息,該消息將被髮送給另外的Channel。 至此一個消息的發送接收流程走完了。消息的確認機制提升了通訊的可靠性。
(1)客戶端鏈接Connection到消息隊列服務器Broker,打開一個channel。
(2)客戶端聲明一個exchange,並設置相關屬性。
(3)客戶端聲明一個queue,並設置相關屬性。
(4)客戶端使用routing key,在exchange和queue之間創建好綁定關係。
(5)客戶端投遞消息到exchange。
MessageQueue、Exchange和Binding構成了AMQP協議的核心。
聲明MessageQueue
在Rabbit MQ中,不管是生產者發送消息仍是消費者接受消息,都首先須要聲明一個MessageQueue。這就存在一個問題,是生產者聲明仍是消費者聲明呢?要解決這個問題,首先須要明確:
a)消費者是沒法訂閱或者獲取不存在的MessageQueue中信息。
b)消息被Exchange接受之後,若是沒有匹配的Queue,則會被丟棄。
在明白了上述兩點之後,就容易理解若是是消費者去聲明Queue,就有可能會出如今聲明Queue以前,生產者已發送的消息被丟棄的隱患。若是應用可以經過消息重發的機制容許消息丟失,則使用此方案沒有任何問題。可是若是不能接受該方案,這就須要不管是生產者仍是消費者,在發送或者接受消息前,都須要去嘗試創建消息隊列。
(重點) 這裏有一點須要明確:
若是一個消費者在一個信道中正在監聽某一個隊列的消息,Rabbit MQ是不容許該消費者在同一個channel去聲明其餘隊列的。Rabbit MQ中,能夠經過queue.declare命令聲明一個隊列,能夠設置該隊列如下屬性:
a) Exclusive:排他隊列,若是一個隊列被聲明爲排他隊列,該隊列僅對首次聲明它的鏈接可見,並在鏈接斷開時自動刪除。這裏須要注意三點:其一,排他隊列是基於鏈接可見的,同一鏈接的不一樣信道是能夠同時訪問同一個鏈接建立的排他隊列的。其二,「首次」,若是一個鏈接已經聲明瞭一個排他隊列,其餘鏈接是不容許創建同名的排他隊列的,這個與普通隊列不一樣。其三,即便該隊列是持久化的,一旦鏈接關閉或者客戶端退出,該排他隊列都會被自動刪除的。這種隊列適用於只限於一個客戶端發送讀取消息的應用場景。
b) Auto-delete:自動刪除,若是該隊列沒有任何訂閱的消費者的話,該隊列會被自動刪除。這種隊列適用於臨時隊列。
c) Durable:持久化。
d) 其餘選項,例如若是用戶僅僅想查詢某一個隊列是否已存在,若是不存在,不想創建該隊列,仍然能夠調用queue.declare,只不過須要將參數passive設爲true,傳給queue.declare,若是該隊列已存在,則會返回true;若是不存在,則會返回Error,可是不會建立新的隊列。
生產者在發送消息時,都須要指定一個RoutingKey和Exchange,Exchange在接到該RoutingKey之後,會判斷該ExchangeType,而後轉發到對應的Queue中,因此發消息不須要指定Queue,彷佛消費者能夠指定Queue綁定到某個RoutingKey和某個Exchange,也能夠不指定Queue,就只根據某個Exchange和某個RoutingKey接受到消息。
exchange 將消息發送到哪個queue是由exchange type 和 Binding綁定規則決定的,目前經常使用的有3種exchange,Direct exchange, Fanout exchange, Topic exchange 。
Direct exchange 直接轉發路由,其實現原理是會將消息中的RoutingKey與該Exchange關聯的全部Binding中的BindingKey進行比較,若是相等,則發送到該Binding對應的Queue中。
Fanout exchange 複製分發路由,該路由不須要RoutingKey,會將消息發送給全部與該 Exchange 定義過Binding的全部Queues中去,實際上是一種廣播行爲。
topic exchange 通配路由,是direct exchange的通配符模式,消息中的RoutingKey能夠寫成通配的模式,exchange支持「#」和「*」 的通配。收到消息後,將消息轉發給全部符合匹配正則表達式的Queue。
須要注意的一點只有queue具備保存消息的功能,exchange不能保存消息。
https://www.cnblogs.com/theRhyme/p/10071781.html
http://www.javashuo.com/article/p-njifrvnw-mn.html
場景: 訂單下單30min若是沒有付款就刪除該訂單
經過消息過時後進入死信交換器,再由交換器轉發到延遲消費隊列(重定向隊列),實現延遲功能;
使用 rabbitmq_delayed_message_exchange 插件實現延遲功能。
代碼:http://www.javashuo.com/article/p-rrimoagi-mo.html
RabbitMQ 生產者將數據發送到 RabbitMQ 的時候,可能數據在網絡傳輸中搞丟了,這個時候 RabbitMQ 收不到消息,消息就丟了。
RabbitMQ 提供了兩種方式來解決這個問題:
事務方式:在生產者發送消息以前,經過`channel.txSelect`開啓一個事務,接着發送消息。
若是消息沒有成功被 RabbitMQ 接收到,生產者會收到異常,此時就能夠進行事務回滾`channel.txRollback`,而後從新發送。假如 RabbitMQ 收到了這個消息,就能夠提交事務`channel.txCommit`。
可是這樣一來,生產者的吞吐量和性能都會下降不少,如今通常不這麼幹。
另一種方式就是經過 Confirm 機制:這個 Confirm 模式是在生產者那裏設置的,就是每次發消息的時候會分配一個惟一的 ID,而後 RabbitMQ服務端 收到以後會回傳一個 ACK,告訴生產者這個消息 OK 了。
若是 RabbitMQ 沒有處理到這個消息,那麼就回調一個 Nack 的接口,這個時候生產者就能夠重發。
事務機制和 Confirm 機制最大的不一樣在於事務機制是同步的,提交一個事務以後會阻塞在那兒。
可是 Confirm 機制是異步的,發送一個消息以後就能夠發送下一個消息,而後那個消息 RabbitMQ 接收了以後會異步回調你一個接口通知你這個消息接收到了。
因此通常在生產者這塊避免數據丟失,都是用 Confirm 機制的。
以上四個條件都知足才能保證消息持久化成功。
持久化的缺點就是下降了服務器的吞吐量,由於使用的是磁盤而非內存存儲,從而下降了吞吐量。可儘可能使用 ssd 硬盤來緩解吞吐量的問題。
TODO待寫
來源:
http://www.javashuo.com/article/p-zcdowiti-gw.html
http://www.javashuo.com/article/p-qalwxbqb-hh.html
http://www.javashuo.com/article/p-sahvupop-hq.html