天天看點

springboot(八):RabbitMQ詳解

rabbitmq 即一個消息隊列,主要是用來實作應用程式的異步和解耦,同時也能起到消息緩沖,消息分發的作用。

消息中間件在網際網路公司的使用中越來越多,剛才還看到新聞阿裡将rocketmq捐獻給了apache,當然了今天的主角還是講rabbitmq。消息中間件最主要的作用是解耦,中間件最标準的用法是生産者生産消息傳送到隊列,消費者從隊列中拿取消息并處理,生産者不用關心是誰來消費,消費者不用關心誰在生産消息,進而達到解耦的目的。在分布式的系統中,消息隊列也會被用在很多其它的方面,比如:分布式事務的支援,rpc的調用等等。

以前一直使用的是activemq,在實際的生産使用中也出現了一些小問題,在網絡查閱了很多的資料後,決定嘗試使用rabbitmq來替換activemq,rabbitmq的高可用性、高性能、靈活性等一些特點吸引了我們,查閱了一些資料整理出此文。

rabbitmq是實作amqp(進階消息隊列協定)的消息中間件的一種,最初起源于金融系統,用于在分布式系統中存儲轉發消息,在易用性、擴充性、高可用性等方面表現不俗。rabbitmq主要是為了實作系統之間的雙向解耦而實作的。當生産者大量産生資料時,消費者無法快速消費,那麼需要一個中間層。儲存這個資料。

amqp,即advanced message queuing protocol,進階消息隊列協定,是應用層協定的一個開放标準,為面向消息的中間件設計。消息中間件主要用于元件之間的解耦,消息的發送者無需知道消息使用者的存在,反之亦然。amqp的主要特征是面向消息、隊列、路由(包括點對點和釋出/訂閱)、可靠性、安全。

rabbitmq是一個開源的amqp實作,伺服器端用erlang語言編寫,支援多種用戶端,如:python、ruby、.net、java、jms、c、php、actionscript、xmpp、stomp等,支援ajax。用于在分布式系統中存儲轉發消息,在易用性、擴充性、高可用性等方面表現不俗。

通常我們談到隊列服務, 會有三個概念: 發消息者、隊列、收消息者,rabbitmq 在這個基本概念之上, 多做了一層抽象, 在發消息者和 隊列之間, 加入了交換器 (exchange). 這樣發消息者和隊列就沒有直接聯系, 轉而變成發消息者把消息給交換器, 交換器根據排程政策再把消息再給隊列。

springboot(八):RabbitMQ詳解

左側 p 代表 生産者,也就是往 rabbitmq 發消息的程式。

中間即是 rabbitmq,其中包括了 交換機 和 隊列。

右側 c 代表 消費者,也就是往 rabbitmq 拿消息的程式。

那麼,其中比較重要的概念有 4 個,分别為:虛拟主機,交換機,隊列,和綁定。

虛拟主機:一個虛拟主機持有一組交換機、隊列和綁定。為什麼需要多個虛拟主機呢?很簡單,rabbitmq當中,使用者隻能在虛拟主機的粒度進行權限控制。 是以,如果需要禁止a組通路b組的交換機/隊列/綁定,必須為a和b分别建立一個虛拟主機。每一個rabbitmq伺服器都有一個預設的虛拟主機“/”。

交換機:exchange 用于轉發消息,但是它不會做存儲 ,如果沒有 queue bind 到 exchange 的話,它會直接丢棄掉 producer 發送過來的消息。 這裡有一個比較重要的概念:路由鍵 。消息到交換機的時候,互動機會轉發到對應的隊列中,那麼究竟轉發到哪個隊列,就要根據該路由鍵。

綁定:也就是交換機需要和隊列相綁定,這其中如上圖所示,是多對多的關系。

交換機的功能主要是接收消息并且轉發到綁定的隊列,交換機不存儲消息,在啟用ack模式後,交換機找不到隊列會傳回錯誤。交換機有四種類型:direct, topic, headers and fanout

direct:direct 類型的行為是”先比對, 再投送”. 即在綁定時設定一個 routing_key, 消息的routing_key 比對時, 才會被交換器投送到綁定的隊列中去.

topic:按規則轉發消息(最靈活)

headers:設定header attribute參數類型的交換機

fanout:轉發消息到所有綁定隊列

direct exchange是rabbitmq預設的交換機模式,也是最簡單的模式,根據key全文比對去尋找隊列。

springboot(八):RabbitMQ詳解

第一個 x - q1 就有一個 binding key,名字為 orange; x - q2 就有 2 個 binding key,名字為 black 和 green。當消息中的 路由鍵 和 這個 binding key 對應上的時候,那麼就知道了該消息去到哪一個隊列中。

ps:為什麼 x 到 q2 要有 black,green,2個 binding key呢,一個不就行了嗎? - 這個主要是因為可能又有 q3,而q3隻接受 black 的資訊,而q2不僅接受black 的資訊,還接受 green 的資訊。

topic exchange 轉發消息主要是根據通配符。 在這種交換機下,隊列和交換機的綁定會定義一種路由模式,那麼,通配符就要在這種路由模式和路由鍵之間比對後交換機才能轉發消息。

在這種交換機模式下:

路由鍵必須是一串字元,用句号(.) 隔開,比如說 agreements.us,或者 agreements.eu.stockholm 等。

路由模式必須包含一個 星号(),主要用于比對路由鍵指定位置的一個單詞,比如說,一個路由模式是這樣子:agreements..b.,那麼就隻能比對路由鍵是這樣子的:第一個單詞是 agreements,第四個單詞是 b。 井号(#)就表示相當于一個或者多個單詞,例如一個比對模式是agreements.eu.berlin.#,那麼,以agreements.eu.berlin開頭的路由鍵都是可以的。

具體代碼發送的時候還是一樣,第一個參數表示交換機,第二個參數表示routing key,第三個參數即消息。如下:

topic 和 direct 類似, 隻是比對上支援了”模式”, 在”點分”的 routing_key 形式中, 可以使用兩個通配符:

*表示一個詞.

#表示零個或多個詞.

headers 也是根據規則比對, 相較于 direct 和 topic 固定地使用 routing_key , headers 則是一個自定義比對規則的類型. 在隊列與交換器綁定時, 會設定一組鍵值對規則, 消息中也包括一組鍵值對( headers 屬性), 當這些鍵值對有一對, 或全部比對時, 消息被投送到對應隊列.

fanout exchange 消息廣播的模式,不管路由鍵或者是路由模式,會把消息發給綁定給它的全部隊列,如果配置了routing_key會被忽略。

springboot內建rabbitmq非常簡單,如果隻是簡單的使用配置非常少,springboot提供了spring-boot-starter-amqp項目對消息各種支援。

1、配置pom包,主要是添加spring-boot-starter-amqp的支援

2、配置檔案

配置rabbitmq的安裝位址、端口以及賬戶資訊

3、隊列配置

發送者

rabbittemplate是springboot 提供的預設實作

4、接收者

5、測試

注意,發送者和接收者的queue name必須一緻,不然不能接收

一個發送者,n個接收者或者n個發送者和n個接收者會出現什麼情況呢?

對上面的代碼進行了小改造,接收端注冊了兩個receiver,receiver1和receiver2,發送端加入參數計數,接收端列印接收到的參數,下面是測試代碼,發送一百條消息,來觀察兩個接收端的執行效果

結果如下:

根據傳回結果得到以下結論

一個發送者,n個接受者,經過測試會均勻的将消息發送到n個接收者中

複制了一份發送者,加入标記,在一百個循環中互相交替發送

結論:和一對多一樣,接收端仍然會均勻接收到消息

springboot以及完美的支援對象的發送和接收,不需要格外的配置。

topic 是rabbitmq中最靈活的一種方式,可以根據routing_key自由的綁定不同的隊列

首先對topic規則配置,這裡使用兩個隊列來測試

使用queuemessages同時比對兩個隊列,queuemessage隻比對”topic.message”隊列

發送send1會比對到topic.#和topic.message 兩個receiver都可以收到消息,發送send2隻有topic.#可以比對所有隻有receiver2監聽到消息

fanout 就是我們熟悉的廣播模式或者訂閱模式,給fanout交換機發送消息,綁定了這個交換機的所有隊列都收到這個消息。

fanout 相關配置

這裡使用了a、b、c三個隊列綁定到fanout交換機上面,發送端的routing_key寫任何字元都會被忽略:

結果說明,綁定到fanout交換機上面的隊列都收到了消息

作者:純潔的微笑

<a href="https://z.clouderwork.com/article/5f016951b157cbaa">原文連結</a>