歡迎光臨
每天分享高質量文章

【訊息佇列 MQ 專欄】訊息佇列之 RabbitMQ —— 集群原理與搭建篇

點擊上方“芋道原始碼”,選擇“置頂公眾號”

技術文章第一時間送達!

原始碼精品專欄

 

一般來說,如果只是為了學習RabbitMQ或者驗證業務工程的正確性那麼在本地環境或者測試環境上使用其單實體部署就可以了,但是出於MQ中間件本身的可靠性、併發性、吞吐量和訊息堆積能力等問題的考慮,在生產環境上一般都會考慮使用RabbitMQ的集群方案。

對於RabbitMQ這麼成熟的訊息佇列產品來說,搭建它並不難並且也有不少童鞋寫過如何搭建RabbitMQ訊息佇列集群的博文,但可能仍然有童鞋並不瞭解其背後的原理,這會導致其遇到性能問題時無法對集群進行進一步的調優。本篇主要介紹RabbitMQ集群方案的原理,如何搭建具備負載均衡能力的中小規模RabbitMQ集群,並最後給出生產環境構建一個能夠具備高可用、高可靠和高吞吐量的中小規模RabbitMQ集群設計方案。

一、RabbitMQ集群方案的原理

RabbitMQ這款訊息佇列中間件產品本身是基於Erlang編寫,Erlang語言天生具備分佈式特性(通過同步Erlang集群各節點的magic cookie來實現)。因此,RabbitMQ天然支持Clustering。這使得RabbitMQ本身不需要像ActiveMQ、Kafka那樣通過ZooKeeper分別來實現HA方案和儲存集群的元資料。集群是保證可靠性的一種方式,同時可以通過水平擴展以達到增加訊息吞吐量能力的目的。下麵先來看下RabbitMQ集群的整體方案:上面圖中採用三個節點組成了一個RabbitMQ的集群,Exchange A(交換器,對於RabbitMQ基礎概念不太明白的童鞋可以看下基礎概念)的元資料信息在所有節點上是一致的,而Queue(存放訊息的佇列)的完整資料則只會存在於它所創建的那個節點上。,其他節點只知道這個queue的metadata信息和一個指向queue的owner node的指標。

(1)RabbitMQ集群元資料的同步

RabbitMQ集群會始終同步四種型別的內部元資料(類似索引):
a.佇列元資料:佇列名稱和它的屬性;
b.交換器元資料:交換器名稱、型別和屬性;
c.系結元資料:一張簡單的表格展示瞭如何將訊息路由到佇列;
d.vhost元資料:為vhost內的佇列、交換器和系結提供命名空間和安全屬性;
因此,當用戶訪問其中任何一個RabbitMQ節點時,通過rabbitmqctl查詢到的queue/user/exchange/vhost等信息都是相同的。

(2)為何RabbitMQ集群僅採用元資料同步的方式

我想肯定有不少同學會問,想要實現HA方案,那將RabbitMQ集群中的所有Queue的完整資料在所有節點上都儲存一份不就可以了麽?(可以類似MySQL的主主樣式嘛)這樣子,任何一個節點出現故障或者宕機不可用時,那麼使用者的客戶端只要能連接至其他節點能夠照常完成訊息的發佈和訂閱嘛。
我想RabbitMQ的作者這麼設計主要還是基於集群本身的性能和儲存空間上來考慮。第一,儲存空間,如果每個集群節點都擁有所有Queue的完全資料拷貝,那麼每個節點的儲存空間會非常大,集群的訊息積壓能力會非常弱(無法通過集群節點的擴容提高訊息積壓能力);第二,性能,訊息的發佈者需要將訊息複製到每一個集群節點,對於持久化訊息,網絡和磁盤同步複製的開銷都會明顯增加。

(3)RabbitMQ集群發送/訂閱訊息的基本原理

RabbitMQ集群的工作原理圖如下:

場景1、客戶端直接連接佇列所在節點

如果有一個訊息生產者或者訊息消費者通過amqp-client的客戶端連接至節點1進行訊息的發佈或者訂閱,那麼此時的集群中的訊息收發只與節點1相關,這個沒有任何問題;如果客戶端相連的是節點2或者節點3(佇列1資料不在該節點上),那麼情況又會是怎麼樣呢?

場景2、客戶端連接的是非佇列資料所在節點

如果訊息生產者所連接的是節點2或者節點3,此時佇列1的完整資料不在該兩個節點上,那麼在發送訊息過程中這兩個節點主要起了一個路由轉發作用,根據這兩個節點上的元資料(也就是上文提到的:指向queue的owner node的指標)轉發至節點1上,最終發送的訊息還是會儲存至節點1的佇列1上。
同樣,如果訊息消費者所連接的節點2或者節點3,那這兩個節點也會作為路由節點起到轉發作用,將會從節點1的佇列1中拉取訊息進行消費。

二、RabbitMQ集群的搭建

(1)搭建RabbitMQ集群所需要安裝的組件

在搭建RabbitMQ集群之前有必要在每台虛擬機上安裝如下的組件包,分別如下:

a.Jdk 1.8

b.Erlang運行時環境,這裡用的是otpsrc19.3.tar.gz (200MB+)

c.RabbitMq的Server組件,這裡用的rabbitmq-server-generic-unix-3.6.10.tar.gz

關於如何安裝上述三個組件的具體步驟,已經有不少博文對此進行了非常詳細的描述,那麼本文就不再贅述了。有需要的同學可以具體參考這些步驟來完成安裝。

(2)搭建10節點組成的RabbitMQ集群

該節中主要展示的是集群搭建,需要確保每台機器上正確安裝了上述三種組件,並且每台虛擬機上的RabbitMQ的實體能夠正常啟動起來。
a.編輯每台RabbitMQ的cookie檔案,以確保各個節點的cookie檔案使用的是同一個值,可以scp其中一臺機器上的cookie至其他各個節點,cookie的預設路徑為/var/lib/rabbitmq/.erlang.cookie或者$HOME/.erlang.cookie,節點之間通過cookie確定相互是否可通信。
b.配置各節點的hosts檔案( vim /etc/hosts)

  1. xxx.xxx.xxx.xxx rmq-broker-test-1

  2. xxx.xxx.xxx.xxx rmq-broker-test-2

  3. xxx.xxx.xxx.xxx rmq-broker-test-3

  4. ......

  5. xxx.xxx.xxx.xxx rmq-broker-test-10

c.逐個節點啟動RabbitMQ服務

  1. rabbitmq-server -detached

d.查看各個節點和集群的工作運行狀態

  1. rabbitmqctl status, rabbitmqctl cluster_status

e.以rmq-broker-test-1為主節點,在rmq-broker-test-2上:

  1. rabbitmqctl stop_app

  2. rabbitmqctl reset

  3. rabbitmqctl join_cluster rabbit@rmq-broker-test-2

  4. rabbitmqctl start_app

在其餘的節點上的操作步驟與rmq-broker-test-2虛擬機上的一樣。 

f.在RabbitMQ集群中的節點只有兩種型別:記憶體節點/磁盤節點,單節點系統只運行磁盤型別的節點。而在集群中,可以選擇配置部分節點為記憶體節點。
記憶體節點將所有的佇列,交換器,系結關係,用戶,權限,和vhost的元資料信息儲存在記憶體中。而磁盤節點將這些信息儲存在磁盤中,但是記憶體節點的性能更高,為了保證集群的高可用性,必須保證集群中有兩個以上的磁盤節點,來保證當有一個磁盤節點崩潰了,集群還能對外提供訪問服務。在上面的操作中,可以通過如下的方式,設置新加入的節點為記憶體節點還是磁盤節點:

  1. #加入時候設置節點為記憶體節點(預設加入的為磁盤節點)

  2. [root@mq-testvm1 ~]# rabbitmqctl join_cluster rabbit@rmq-broker-test-1 --ram

  1. #也通過下麵方式修改的節點的型別

  2. [root@mq-testvm1 ~]# rabbitmqctl changeclusternode_type disc | ram

g.最後可以通過“rabbitmqctl cluster_status”的方式來查看集群的狀態,上面搭建的10個節點的RabbitMQ集群狀態(3個節點為磁盤節點,7個節點為記憶體節點)如下:

  1. Cluster status of node 'rabbit@rmq-broker-test-1'

  2. [{nodes,[{disc,['rabbit@rmq-broker-test-1','rabbit@rmq-broker-test-2',

  3.                'rabbit@rmq-broker-test-3']},

  4.         {ram,['rabbit@rmq-broker-test-9','rabbit@rmq-broker-test-8',

  5.               'rabbit@rmq-broker-test-7','rabbit@rmq-broker-test-6',

  6.               'rabbit@rmq-broker-test-5','rabbit@rmq-broker-test-4',

  7.               'rabbit@rmq-broker-test-10']}]},

  8. {running_nodes,['rabbit@rmq-broker-test-10','rabbit@rmq-broker-test-5',

  9.                 'rabbit@rmq-broker-test-9','rabbit@rmq-broker-test-2',

  10.                 'rabbit@rmq-broker-test-8','rabbit@rmq-broker-test-7',

  11.                 'rabbit@rmq-broker-test-6','rabbit@rmq-broker-test-3',

  12.                 'rabbit@rmq-broker-test-4','rabbit@rmq-broker-test-1']},

  13. {cluster_name,<<"rabbit@mq-testvm1">>},

  14. {partitions,[]},

  15. {alarms,[{'rabbit@rmq-broker-test-10',[]},

  16.          {'rabbit@rmq-broker-test-5',[]},

  17.          {'rabbit@rmq-broker-test-9',[]},

  18.          {'rabbit@rmq-broker-test-2',[]},

  19.          {'rabbit@rmq-broker-test-8',[]},

  20.          {'rabbit@rmq-broker-test-7',[]},

  21.          {'rabbit@rmq-broker-test-6',[]},

  22.          {'rabbit@rmq-broker-test-3',[]},

  23.          {'rabbit@rmq-broker-test-4',[]},

  24.          {'rabbit@rmq-broker-test-1',[]}]}]

(3)配置HAProxy

HAProxy提供高可用性、負載均衡以及基於TCP和HTTP應用的代理,支持虛擬主機,它是免費、快速並且可靠的一種解決方案。根據官方資料,其最高極限支持10G的併發。HAProxy支持從4層至7層的網絡交換,即改寫所有的TCP協議。就是說,Haproxy 甚至還支持 Mysql 的均衡負載。為了實現RabbitMQ集群的軟負載均衡,這裡可以選擇HAProxy。
關於HAProxy如何安裝的文章之前也有很多同學寫過,這裡就不再贅述了,有需要的同學可以參考下網上的做法。這裡主要說下安裝完HAProxy組件後的具體配置。
HAProxy使用單一配置檔案來定義所有屬性,包括從前端IP到後端服務器。下麵展示了用於7個RabbitMQ節點組成集群的負載均衡配置(另外3個磁盤節點用於儲存集群的配置和元資料,不做負載)。同時,HAProxy運行在另外一臺機器上。HAProxy的具體配置如下:

  1. #全域性配置

  2. global

  3.        #日誌輸出配置,所有日誌都記錄在本機,通過local0輸出

  4.        log 127.0.0.1 local0 info

  5.        #最大連接數

  6.        maxconn 4096

  7.        #改變當前的工作目錄

  8.        chroot /apps/svr/haproxy

  9.        #以指定的UID運行haproxy行程

  10.        uid 99

  11.        #以指定的GID運行haproxy行程

  12.        gid 99

  13.        #以守護行程方式運行haproxy #debug #quiet

  14.        daemon

  15.        #debug

  16.        #當前行程pid檔案

  17.        pidfile /apps/svr/haproxy/haproxy.pid

  18. #預設配置

  19. defaults

  20.        #應用全域性的日誌配置

  21.        log global

  22.        #預設的樣式mode{tcp|http|health}

  23.        #tcp是4層,http是7層,health只傳回OK

  24.        mode tcp

  25.        #日誌類別tcplog

  26.        option tcplog

  27.        #不記錄健康檢查日誌信息

  28.        option dontlognull

  29.        #3次失敗則認為服務不可用

  30.        retries 3

  31.        #每個行程可用的最大連接數

  32.        maxconn 2000

  33.        #連接超時

  34.        timeout connect 5s

  35.        #客戶端超時

  36.        timeout client 120s

  37.        #服務端超時

  38.        timeout server 120s

  39.        maxconn 2000

  40.        #連接超時

  41.        timeout connect 5s

  42.        #客戶端超時

  43.        timeout client 120s

  44.        #服務端超時

  45.        timeout server 120s

  46. #系結配置

  47. listen rabbitmq_cluster

  48.        bind 0.0.0.0:5672

  49.        #配置TCP樣式

  50.        mode tcp

  51.        #加權輪詢

  52.        balance roundrobin

  53.        #RabbitMQ集群節點配置,其中ip1~ip7為RabbitMQ集群節點ip地址

  54.        server rmq_node1 ip1:5672 check inter 5000 rise 2 fall 3 weight 1

  55.        server rmq_node2 ip2:5672 check inter 5000 rise 2 fall 3 weight 1

  56.        server rmq_node3 ip3:5672 check inter 5000 rise 2 fall 3 weight 1

  57.        server rmq_node4 ip4:5672 check inter 5000 rise 2 fall 3 weight 1

  58.        server rmq_node5 ip5:5672 check inter 5000 rise 2 fall 3 weight 1

  59.        server rmq_node6 ip6:5672 check inter 5000 rise 2 fall 3 weight 1

  60.        server rmq_node7 ip7:5672 check inter 5000 rise 2 fall 3 weight 1

  61. #haproxy監控頁面地址

  62. listen monitor

  63.        bind 0.0.0.0:8100

  64.        mode http

  65.        option httplog

  66.        stats enable

  67.        stats uri /stats

  68.        stats refresh 5s

在上面的配置中“listen rabbitmqcluster bind 0.0.0.0:5671”這裡定義了客戶端連接IP地址和端口號。這裡配置的負載均衡演算法是roundrobin—加權輪詢。與配置RabbitMQ集群負載均衡最為相關的是“ server rmqnode1 ip1:5672 check inter 5000 rise 2 fall 3 weight 1”這種,它標識並且定義了後端RabbitMQ的服務。主要含義如下:

(a)“server”部分:定義HAProxy內RabbitMQ服務的標識;
(b)“ip1:5672”部分:標識了後端RabbitMQ的服務地址;
(c)“check inter”部分:表示每隔多少毫秒檢查RabbitMQ服務是否
可用;
(d)“rise”部分:表示RabbitMQ服務在發生故障之後,需要多少次健康檢查才能被再次確認可用;
(e)“fall”部分:表示需要經歷多少次失敗的健康檢查之後,HAProxy才會停止使用此RabbitMQ服務。

  1. #啟用HAProxy服務

  2. [root@mq-testvm12 conf]# haproxy -f haproxy.cfg

啟動後,即可看到如下的HAproxy的界面圖:

(4)RabbitMQ的集群架構設計圖

經過上面的RabbitMQ10個節點集群搭建和HAProxy軟彈性負載均衡配置後即可組建一個中小規模的RabbitMQ集群了,然而為了能夠在實際的生產環境使用還需要根據實際的業務需求對集群中的各個實體進行一些性能引數指標的監控,從性能、吞吐量和訊息堆積能力等角度考慮,可以選擇Kafka來作為RabbitMQ集群的監控佇列使用。因此,這裡先給出了一個中小規模RabbitMQ集群架構設計圖:對於訊息的生產和消費者可以通過HAProxy的軟負載將請求分發至RabbitMQ集群中的Node1~Node7節點,其中Node8~Node10的三個節點作為磁盤節點儲存集群元資料和配置信息。鑒於篇幅原因這裡就不在對監控部分進行詳細的描述的,會在後續篇幅中對如何使用RabbitMQ的HTTP API接口進行監控資料統計進行詳細闡述。

三、總結

本文主要詳細介紹了RabbitMQ集群的工作原理和如何搭建一個具備負載均衡能力的中小規模RabbitMQ集群的方法,並最後給出了RabbitMQ集群的架構設計圖。限於筆者的才疏學淺,對本文內容可能還有理解不到位的地方,如有闡述不合理之處還望留言一起探討。

在此順便為自己打個Call,有興趣的朋友可以關註下我的個人公眾號:“匠心獨運的博客”,對於Java併發、Spring和資料庫的一些細節、問題的文章將會在這個公眾號上發佈,歡迎交流與討論。


知識星球

目前在知識星球(https://t.zsxq.com/2VbiaEu)更新瞭如下 Dubbo 原始碼解析如下:

01. 除錯環境搭建
02. 專案結構一覽
03. API 配置(一)之應用
04. API 配置(二)之服務提供者
05. API 配置(三)之服務消費者
06. 屬性配置
07. XML 配置
08. 核心流程一覽

09. 拓展機制 SPI

10. 執行緒池

...
一共 60 篇++

赞(0)

分享創造快樂

© 2022 知識星球   网站地图