1. 程式人生 > >RabbitMQ原理分析

RabbitMQ原理分析

RabbitMQ 簡介

基於AMQP協議實現,主要作用是解耦,冗餘,擴充套件性(增大訊息入隊和處理的頻率變得很容易),平滑峰值,可恢復性,送達保證(ACK機制 消費者消費訊息後必須返回相應的ACK),順序保證等.

文章當中使用的RabbitMQ的版本是RabbitMQ 3.6.6.

關鍵概念

Exchange交換機

啟動RabbitMQ相關的服務,會預設建立一個不可以刪除的Exchange.
繫結規則:RoutingKey與佇列名稱相等(Direct).

生產者將他們生產的訊息推入到交換機中,交換機決定將訊息傳送至下一個交換機或者是佇列.
一般的情況都是一個交換機繫結的多個佇列.交換機繫結交換機的會使資料流變的複雜,這種情況在一些業務場景可能會需要用到.

分為四種交換機型別:
BindingKey 是指與佇列或交換機與交換機繫結的Key,根據相應的規則與RoutingKey進行匹配.
RoutingKey是指生產者告知Rabbit的路由Key.

1.Direct exchange (直接交換)
如果 Binding key 匹配, 那麼Message就會被傳遞到相應的queue中.

2.Fanout exchange(廣播型別)
多個佇列會接收到這個訊息
會向響應的queue廣播。

3.Topic exchange (對key進行模式匹配)
routing key為一個句點號”.”分隔的字串(我們將被句點號“. ”分隔開的每一段獨立的字串稱為一個單詞)

*:注意這個只是匹配一個單詞,要注意與正則匹配的中的概念進行區分.
#:匹配一個或多個單詞.

如BindingKey:”TEST.TOPICB”、”TEST.TOPICA”, “TEST.TOPIC.A”, 那麼我們設定Routing Key 設定為 “TEST.*” 那麼會匹配 “TEST.TOPICB”、”TEST.TOPICA”.
如果設定Routing Key為”TEST.#” 那麼會匹配”TEST.TOPIC.A”.

4.headers(通過headers裡的鍵值對進行路由)
這裡需要了解一下RabbitMQ的協議,可以通過rabbitmq官網下載AMQP協議.
headers型別的Exchange不依賴於routing key匹配規則來路由訊息,而是根據傳送的訊息內容中的headers屬性進行匹配。
在繫結Queue與Exchange時指定一組鍵值對;當訊息傳送到Exchange時,RabbitMQ會取到該訊息的headers(也是一個鍵值對的形式),對比其中的鍵值對是否完全匹配Queue與Exchange繫結時指定的鍵值對.如果完全匹配則訊息會路由到該Queue,否則不會路由到該Queue。

如果沒有佇列繫結在交換機上,則傳送到該交換機上的訊息會丟失。
一個交換機可以繫結多個佇列,一個佇列可以被多個交換機繫結。
交換也可以互相進行繫結.但是一般情況下不推薦這樣做,複雜情況下會使資料流變得難以理解.

Queue:佇列

佇列裡儲存訊息,並且被消費者處理訊息.
可以對對應的佇列設定相應的儲存訊息策略,可以設定為持久儲存,也可以設定過期時間.
一個佇列可以有多個消費者,這點需要注意.Kafka當中的消費者不能存在多個,但是可以有多個消費者組.
之前說到交換機的概念,我們也可以將資訊直接傳送到指定的隊列當中,這種方式只不過是通過了預設的交換機.

Consumer:消費者

根據AMQP 0-9-1,消費者支援兩種方式消費:
1.推送方式
2.拉取方式

當應用需要丟棄這個訊息(basic.reject)或者是重新入隊(basic.nack),我們可以返回相應的響應.
需要注意的是絕不能在多條訊息消費時(multiple)返回basic.reject.

Binding:繫結

Bindings就是之前提過的交換機中的BindingKey.
繫結是決定訊息該從交換機放入到哪個佇列,或者放到哪個exchange裡面的規則.

Vhsot:虛擬主機

虛擬主機,這個概念與nginx 虛擬域名類似,主要是一些許可權的管理,vhsot的相關配置不可以跨越,完全隔離環境.

每個vhost都有自己的connections, exchanges, queues, bindings等.
因此這個概念與nginx當中的server block中的虛擬域名概念的類似.

Broker/Cluster

一個RabbitMQ broker執行著一組包含著多個或者一個Erlang node,每一個node執行著RabbitMQ 共享使用者 bindings,虛擬主機,佇列交換機等.
這些節點集合稱為叢集.
RabbitMQ叢集當中的節點都是相等的,沒有follower和leader.

RabbitMQ可靠性

接下來寫一些重點需要介紹的內容,可靠性也與可用性息息相關.

ACK與Confirm

ACK機制保證了生產者與消費者標記訊息被處理.
ACK保證了訊息最少傳送一次,當沒有ACK的時候訊息並不算被消費,因此消費者沒有傳送對應的ACK或者斷開了連線那麼訊息會被重新放入到隊列當中.

生產者的Confirm,與消費者的ACK類似,但是需要注意的生產者傳送訊息是多條訊息,所以需要Confirm這個機制來保證訊息被正確接收,還有Transaction機制保證訊息的事務處理.

HeartBeat:心跳包

HeartBeat 作用防止TCP網路連線中斷,幫助RabbitMQServer找出斷開的連線.也可以用來斷開空閒的連線.

消費者與生產者

當消費者失去連線,生產者失去連線或者崩潰,或者RabbitMQ進行了fail over,生產者需要傳送未被ACK的訊息,消費者需要注意重複訊息的處理,儘量確保冪等性.
這樣確保了訊息最大的可靠性,完整性.

這裡需要注意下生產傳送到訊息到多個映象佇列可能會引起一些效能問題,因為需要等待每個佇列的ACK.

RabbitMQ高可用

Rabbit如何保證高可用?
通過映象佇列的方式,當然基於映象佇列還有一些技術保證了高可用,例如事務機制和釋出確認機制,如何新增映象,持久化儲存策略等.

每個映象的佇列有一個MASTER以及一個或多個備用映象.
其中佇列都有自己的MASTER,MASTER會處理讀寫訊息,備用映象不會分擔MASTER讀寫訊息的負載.

每當接受到生產者生產的訊息,MASTER首先會處理訊息,然後推送到備用映象.

HA-MODE

ha-mode 有三種策略:
ha-mode:Excaxtly 通過ha-param 指定具體設定映象的個數的值.如ha-param:2那麼將有叢集中兩個節點會建立備用映象.推薦值為(N/2+1) N為叢集當中的節點個數.
ha-mode:all 會在叢集中的所有節點建立備用映象.一般不推薦.
ha-mode:nodes 通過ha-param指定建立備用映象節點的名稱.如 ha-param:test,那麼在test節點當中會建立映象.

故障恢復機制

當MASTER發生故障後:
1.執行最長時間的備用映象會成為MASTER.如果備用映象中沒有完全同步MASTER中訊息,那麼這些訊息會被丟失.
2.映象會認為之前的消費者都失去了連線,會把已經發送給消費者並等待ACK所有的訊息重新入隊.
3.消費者會被通知故障恢復
4.消費者會消費重複入隊訊息,這裡需要注意
5.當選擇映象變為MASTER時,此時沒有從MASTER同步到備用映象的資料會丟失掉.如果MASTER發生故障,訊息會被髮送到映象,一旦映象成為MASTER,這些訊息會被新增到隊列當中.如果訊息被髮送到映象上,那麼映象會被路由到MASTER進行處理.
6.生產者客戶端傳送的訊息任然需要被確認傳送到生產者.

RabbitMQ的安裝

wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
安裝rpm倉庫
rpm -Uvh erlang-solutions-1.0-1.noarch.rpm‘’
安裝erlang
yum install erlang -y

下載RabbitMQ的rpm,wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.6/rabbitmq-server-3.6.6-1.el6.noarch.rpm
yum install rabbitmq-server-3.6.6-1.el6.noarch.rpm
發現錯誤,安裝依賴Requires: socat 。
更新源wget –no-cache http://www.convirture.com/repos/definitions/rhel/6.x/convirt.repo -O /etc/yum.repos.d/convirt.repo
yum install socat
yum install rabbitmq-server-3.6.6-1.el6.noarch.rpm
rabbitmq-server start

啟動web管理介面
rabbitmq-plugins enable rabbitmq-management
增加外網訪問使用者,預設使用者guest只能本地訪問。
rabbitmqctl add_user admin 123456
設定使用者組
rabbitmqctl set_user_tags admin administrator
設定預設vhost(”/”)訪問許可權
rabbitmqctl set_permissions -p “/” admin “.” “.” “.*”

注意修改在iptables修改相應的埠號

瀏覽器訪問:http://IP:15672

其它

需要注意的是訊息、佇列、交換機的持久化預設是未開啟的,需要滿足的三個條件
1.需要將訊息的 delivery mode 設定為2
2.訊息被送入可持久化的交換機中
3.到達可持久化的佇列中

如何檢視沒有ACK的訊息

sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged

消費者需要注意處理在故障恢復情況下的重複訊息的處理,保證處理的冪等性.在一些場景尤為注意,如下單,轉賬等.