RabbitMQ消息隊列應用

1 RabbitMQ安裝部署

RabbitMQ

這里是ErLang環境的下載地址
http://www.erlang.org/downloads

這是RabbitMQ環境、客戶端、實例和說明文檔的地址
http://www.rabbitmq.com/download.html

默認安裝的Rabbit MQ 監聽端口是:5672

進入目錄
CD D:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.10\sbin

安裝完以后erlang需要手動設置ERLANG_HOME 的系統變量。
set ERLANG_HOME=D:\Program Files\erl9.0

激活Rabbit MQ's Management Plugin
rabbitmq-plugins.bat  enable  rabbitmq_management

創建管理用戶,所有的賬號設置,都是區分大小寫的,千萬注意
rabbitmqctl.bat add_user BOEREms BOEREms1703

設置管理員,設置管理員前,BOEREms這個賬號要先創建,否則設置就會失敗。
rabbitmqctl.bat set_user_tags BOEREms administrator

設置權限
rabbitmqctl.bat set_permissions -p / BOEREms ".*" ".*" ".*"

查詢用戶
rabbitmqctl.bat list_users

查詢vhosts
rabbitmqctl.bat list_vhosts

啟動RabbitMQ服務: 
net stop RabbitMQ && net start RabbitMQ, 可以通過工具啟動和關閉RabbitMQ服務

訪問Rabbit Mq的管理控制臺,使用剛才創建的賬號登陸系統即可。
Rabbit MQ 管理后臺,可以更好的可視化方式查看RabbitMQ服務器實例的狀態。
http://localhost:15672

Virtual Host:UploadQueue
D:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.10\sbin>rabbitmq-plugins.ba
t enable rabbitmq_management
Plugin configuration unchanged.

Applying plugin configuration to rabbit@WIN-7BVDCM2AUG0... failed.
 * Could not contact node rabbit@WIN-7BVDCM2AUG0.
   Changes will take effect at broker restart.
 * Options: --online  - fail if broker cannot be contacted.
            --offline - do not try to contact broker.
D:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.10\sbin>rabbitmqctl status
Status of node 'rabbit@WIN-7BVDCM2AUG0'
Error: unable to connect to node 'rabbit@WIN-7BVDCM2AUG0': nodedown

DIAGNOSTICS
===========

attempted to contact: ['rabbit@WIN-7BVDCM2AUG0']

rabbit@WIN-7BVDCM2AUG0:
  * connected to epmd (port 4369) on WIN-7BVDCM2AUG0
  * epmd reports node 'rabbit' running on port 25672
  * TCP connection succeeded but Erlang distribution failed

  * Authentication failed (rejected by the remote node), please check the Erlang
 cookie


current node details:
- node name: 'rabbitmq-cli-17@WIN-7BVDCM2AUG0'
- home dir: C:\Users\Administrator
- cookie hash: /352utUNRCCPsDbXHre2Dw==
具體操作:將 C:\WINDOWS\.erlang.cookie   同步到RabbitMq 啟動用戶 例如win10:C:\Users\%USERNAME%\.erlang.cookie 

2 RabbitMQ原理簡介

RabbitMQ結構示意
RabbitMQ內部結構

首先這個過程走分三個部分,1、客戶端(生產消息隊列),2、RabbitMQ服務端(負責路由規則的綁定與消息的分發),3、客戶端(消費消息隊列中的消息);由圖可以看出,一個消息可以走一次網絡卻被分發到不同的消息隊列中,然后被多個的客戶端消費,那么這個過程就是RabbitMQ的核心機制,RabbitMQ的路由類型與消費模式。

RabbitMQ中間件分為服務端(RabbitMQ Server)和客戶端(RabbitMQ Client),服務端可以理解為是一個消息的代理消費者,客戶端又分為消息生產者(Producer)和消息消費者(Consumer)

  • 消息生產者(Producer):主要生產消息并將消息基于TCP協議,通過建立Connection和Channel,將消息傳輸給RabbitMQ Server,對于Producer而言基本就完成了工作。
  • 服務端(RabbitMQ Server):主要負責處理消息路由、分發、入隊列、緩存和出列。主要由三部分組成:Exchange、RoutingKey、Queue
  1. Exchange:用于接收消息生產者發送的消息,有三種類型的exchange:direct, fanout,topic,不同類型實現了不同的路由算法;

A. direct exchange:將與routing key 比配的消息,直接推入相對應的隊列,創建隊列時,默認就創建同名的routing key。
B. fanout exchange:是一種廣播模式,忽略routingkey的規則。
C. topic exchange:應用主題,根據key進行模式匹配路由,例如:若為abc則推入到所有abc相對應的queue;若為abc.#則推入到abc.xx.one ,abc.yy.two對應的queue。

  1. RoutingKey:是RabbitMQ實現路由分發到各個隊列的規則,并結合Binging提供于Exchange使用將消息推送入隊列;
  2. Queue:是消息隊列,可以根據需要定義多個隊列,設置隊列的屬性,比如:消息移除、消息緩存、回調機制等設置,實現與Consumer通信;
  • 消息消費者(Consumer):主要負責消費Queue的消息,同樣基于TCP協議,通過建立Connection和Channel與Queue傳輸消息,一個消息可以給多個Consumer消費;
  • 關鍵名詞說明:Connection、Channel、Binging等;
  1. Connection:是建立客戶端與服務端的連接。
  2. Channel:是基于Connection之上建立通信通道,因為每次Connection建立TCP協議通信開銷及性能消耗較大,所以一次建立Connection后,使用多個Channel通道通信減少開銷和提高性能。
  3. Binging:是一個捆綁定義,將exchange和queue捆綁,定義routingkey相關策略。

3 RabbitMQ中的一些名詞闡述與消息從投遞到消費的整個過程

消息從投遞到消費的整個過程(01)

從上圖的標題中可以看到一些陌生的英文單詞,讓我們感覺一無所知,更無從操作,那么我給大家弄啦一個圖片大家可以看下,或許對您理解這些新鮮的單詞有所幫助。

消息從投遞到消費的整個過程(02)

看過這些名詞,之后,或許你還毫無頭緒,那么我把消息從生產到消費的整個流程給大家說一下,或許會更深入一點,其中Exchange,與Queue都是可以設置相關屬性,隊列的持久化,交換器類型制定。

4 RabbitMQ中Exchange的類型

Direct Exchange是RabbitMQ默認的交換機模式,也是最簡單的模式,根據key全文匹配去尋找隊列。
類型有4種,direct,fanout,topic,headers。其中headers不常用,本篇不做介紹,其他三種類型,會做詳細介紹。
那么這些類型是什么意思呢?就是Exchange與隊列進行綁定后,消息根據exchang的類型,按照不同的綁定規則分發消息到消息隊列中,可以是一個消息被分發給多個消息隊列,也可以是一個消息分發到一個消息隊列。具體請看下文。
介紹之初還要說下RoutingKey,這是個什么玩意呢?他是exchange與消息隊列綁定中的一個標識。有些路由類型會按照標識對應消息隊列,有些路由類型忽略routingkey。具體看下文。

  • Exchange類型direct
direct

他是根據交換器名稱與routingkey來找隊列的

rabbitMq_direct

第一個 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 的信息。

Exchange類型direct

Note:消息從client發出,傳送給交換器ChangeA,RoutingKey為routingkey.ZLH,那么不管你發送給Queue1,還是Queue2一個消息都會保存在Queue1,Queue2,Queue3,三個隊列中。這就是交換器的direct類型的路由規則。只要找到路由器與routingkey綁定的隊列,那么他有多少隊列,他就分發給多少隊列

  • Exchange類型fanout
fanout

這個類型忽略Routingkey,他為廣播模式

Exchange類型fanout

Note:消息從客戶端發出,只要queue與exchange有綁定,那么他不管你的Routingkey是什么他都會將消息分發給所有與該exchang綁定的隊列中。

  • Exchange類型topic
topic

這個類型的路由規則如果你掌握啦,那是相當的好用,與靈活。他是根據RoutingKey的設置,來做匹配的,其中這里還有兩個通配符為:

*,代表任意的一個詞。例如topic.zlh.*,他能夠匹配到,topic.zlh.one ,topic.zlh.two ,topic.zlh.abc, ....
#,代表任意多個詞。例如topic.#,他能夠匹配到,topic.zlh.one ,topic.zlh.two ,topic.zlh.abc, ....
Exchange類型topic

Note:這個圖看上去很亂,但是他是根據匹配符做匹配的,這里我建議你自己做下消息隊列的具體操作。

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

5 消息隊列的消費與消息確認Ack

  • 消息隊列的消費
消息隊列的消費

Note:如果一個消息隊列中有大量消息等待操作時,我們可以用多個客戶端來處理消息,這里的分發機制是采用負載均衡算法中的輪詢。第一個消息給A,下一個消息給B,下下一個消息給A,下下下一個消息給B......以此類推。

  • 為啦保證消息的安全性,保證此消息被正確處理后才能在服務端的消息隊列中刪除。那么rabbitmq提供啦ack應答機制,來實現這一功能。ack應答有兩種方式:1、自動應答,2、手動應答

6 AMQP

AMQP(Advanced Message Queuing Protocol)協議是一個高級抽象層消息通信協議,RabbitMQ是AMQP協議的實現。它主要包括以下組件:

AMQ Protocol Model

  1. Server(broker): 接受客戶端連接,實現AMQP消息隊列和路由功能的進程。
  2. Virtual Host:其實是一個虛擬概念,類似于權限控制組,一個Virtual Host里面可以有若干個Exchange和Queue,但是權限控制的最小粒度是Virtual Host。
  3. Exchange:接受生產者發送的消息,并根據Binding規則將消息路由給服務器中的隊列。ExchangeType決定了Exchange路由消息的行為,例如,在RabbitMQ中,ExchangeType有direct、Fanout和Topic三種,不同類型的Exchange路由的行為是不一樣的。
  4. Message Queue:消息隊列,用于存儲還未被消費者消費的消息
  5. Message: 由Header和Body組成,Header是由生產者添加的各種屬性的集合,包括Message是否被持久化、由哪個Message Queue接受、優先級是多少等。而Body是真正需要傳輸的APP數據。
  6. Binding:Binding聯系了Exchange與Message Queue。Exchange在與多個Message Queue發生Binding后會生成一張路由表,路由表中存儲著Message Queue所需消息的限制條件即Binding Key。當Exchange收到Message時會解析其Header得到Routing Key,Exchange根據Routing Key與Exchange Type將Message路由到Message Queue。Binding Key由Consumer在Binding Exchange與Message Queue時指定,而Routing Key由Producer發送Message時指定,兩者的匹配方式由Exchange Type決定。
  7. Connection:連接,對于RabbitMQ而言,其實就是一個位于客戶端和Broker之間的TCP連接
  8. Channel:信道,僅僅創建了客戶端到Broker之間的連接后,客戶端還是不能發送消息的。需要為每一個Connection創建Channel,AMQP協議規定只有通過Channel才能執行AMQP的命令。一個Connection可以包含多個Channel。之所以需要Channel,是因為TCP連接的建立和釋放都是十分昂貴的,如果一個客戶端每一個線程都需要與Broker交互,如果每一個線程都建立一個TCP連接,暫且不考慮TCP連接是否浪費,就算操作系統也無法承受每秒建立如此多的TCP連接。RabbitMQ建議客戶端線程之間不要共用Channel,至少要保證共用Channel的線程發送消息必須是串行的,但是建議盡量共用Connection。
  9. Command:AMQP的命令,客戶端通過Command完成與AMQP服務器的交互來實現自身的邏輯。例如在RabbitMQ中,客戶端可以通過publish命令發送消息,txSelect開啟一個事務,txCommit提交一個事務。

在了解了AMQP模型以后,需要簡單介紹一下AMQP的協議棧,AMQP協議本身包括三層:

AMQP的協議棧
  1. Module Layer,位于協議最高層,主要定義了一些供客戶端調用的命令,客戶端可以利用這些命令實現自己的業務邏輯,例如,客戶端可以通過queue.declare聲明一個隊列,利用consume命令獲取一個隊列中的消息。
  2. Session Layer,主要負責將客戶端的命令發送給服務器,在將服務器端的應答返回給客戶端,主要為客戶端與服務器之間通信提供可靠性、同步機制和錯誤處理。
  3. Transport Layer,主要傳輸二進制數據流,提供幀的處理、信道復用、錯誤檢測和數據表示。

7 RabbitMQ使用場景

場景1:單發送單接收

單發送單接收

使用場景:簡單的發送與接收,沒有特別的處理。

場景2:單發送多接收

單發送多接收

使用場景:一個發送端,多個接收端,如分布式的任務派發。為了保證消息發送的可靠性,不丟失消息,使消息持久化了。同時為了防止接收端在處理消息時down掉,只有在消息處理完成后才發送ack消息。

發送端和場景1不同點

  1. 使用“task_queue”聲明了另一個Queue,因為RabbitMQ不容許聲明2個相同名稱、配置不同的Queue
  2. 使"task_queue"的Queue的durable的屬性為true,即使消息隊列durable
  3. 使用MessageProperties.PERSISTENT_TEXT_PLAIN使消息durable

接收端和場景1不同點

  1. 使用“task_queue”聲明消息隊列,并使消息隊列durable
  2. 在使用channel.basicConsume接收消息時使autoAck為false,即不自動會發ack,由channel.basicAck()在消息處理完成后發送消息。
  3. 使用了channel.basicQos(1)保證在接收端一個消息沒有處理完時不會接收另一個消息,即接收端發送了ack后才會接收下一個消息。在這種情況下發送端會嘗試把消息發送給下一個not busy的接收端。

場景3:Publish/Subscribe

Publish/Subscribe

使用場景:發布、訂閱模式,發送端發送廣播消息,多個接收端接收。

發送端
發送消息到一個名為“logs”的exchange上,使用“fanout”方式發送,即廣播消息,不需要使用queue,發送端不需要關心誰接收。

接收端

  1. 聲明名為“logs”的exchange的,方式為"fanout",和發送端一樣。
  2. channel.queueDeclare().getQueue();該語句得到一個隨機名稱的Queue,該queue的類型為non-durable、exclusive、auto-delete的,將該queue綁定到上面的exchange上接收消息。
  3. 注意binding queue的時候,channel.queueBind()的第三個參數Routing key為空,即所有的消息都接收。如果這個值不為空,在exchange type為“fanout”方式下該值被忽略!

場景4:Routing (按路線發送接收)

按路線發送接收

使用場景:發送端按routing key發送消息,不同的接收端按不同的routing key接收消息。

發送端和場景3的區別

  1. exchange的type為direct
  2. 發送消息的時候加入了routing key

接收端和場景3的區別
在綁定queue和exchange的時候使用了routing key,即從該exchange上只接收routing key指定的消息。

場景5:Topics (按topic發送接收)

按topic發送接收

使用場景:發送端不只按固定的routing key發送消息,而是按字符串“匹配”發送,接收端同樣如此。

發送端和場景4的區別

  1. exchange的type為topic
  2. 發送消息的routing key不是固定的單詞,而是匹配字符串,如".lu.#",匹配一個單詞,#匹配0個或多個單詞。

接收端和場景4的區別

  1. exchange的type為topic
  2. 接收消息的routing key不是固定的單詞,而是匹配字符串。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. 歷史 RabbitMQ是一個由erlang開發的AMQP(Advanced Message Queue )的...
    高廣超閱讀 6,117評論 3 51
  • 來源 RabbitMQ是用Erlang實現的一個高并發高可靠AMQP消息隊列服務器。支持消息的持久化、事務、擁塞控...
    jiangmo閱讀 10,406評論 2 34
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • rabbitMQ是一款基于AMQP協議的消息中間件,它能夠在應用之間提供可靠的消息傳輸。在易用性,擴展性,高可用性...
    點融黑幫閱讀 3,039評論 3 41
  • 關于消息隊列,從前年開始斷斷續續看了些資料,想寫很久了,但一直沒騰出空,近來分別碰到幾個朋友聊這塊的技術選型,是時...
    預流閱讀 585,447評論 51 786