Rabbitmq集群高可用测试
Rabbitmq集群高可用
RabbitMQ是用erlang開(kāi)發(fā)的,集群非常方便,因?yàn)閑rlang天生就是一門分布式語(yǔ)言,但其本身并不支持負(fù)載均衡。
Rabbit模式大概分為以下三種:單一模式、普通模式、鏡像模式
單一模式:最簡(jiǎn)單的情況,非集群模式。
沒(méi)什么好說(shuō)的。
普通模式:默認(rèn)的集群模式。
對(duì)于Queue來(lái)說(shuō),消息實(shí)體只存在于其中一個(gè)節(jié)點(diǎn),A、B兩個(gè)節(jié)點(diǎn)僅有相同的元數(shù)據(jù),即隊(duì)列結(jié)構(gòu)。
當(dāng)消息進(jìn)入A節(jié)點(diǎn)的Queue中后,consumer從B節(jié)點(diǎn)拉取時(shí),RabbitMQ會(huì)臨時(shí)在A、B間進(jìn)行消息傳輸,把A中的消息實(shí)體取出并經(jīng)過(guò)B發(fā)送給consumer。
所以consumer應(yīng)盡量連接每一個(gè)節(jié)點(diǎn),從中取消息。即對(duì)于同一個(gè)邏輯隊(duì)列,要在多個(gè)節(jié)點(diǎn)建立物理Queue。否則無(wú)論consumer連A或B,出口總在A,會(huì)產(chǎn)生瓶頸。
該模式存在一個(gè)問(wèn)題就是當(dāng)A節(jié)點(diǎn)故障后,B節(jié)點(diǎn)無(wú)法取到A節(jié)點(diǎn)中還未消費(fèi)的消息實(shí)體。
如果做了消息持久化,那么得等A節(jié)點(diǎn)恢復(fù),然后才可被消費(fèi);如果沒(méi)有持久化的話,然后就沒(méi)有然后了……
鏡像模式:把需要的隊(duì)列做成鏡像隊(duì)列,存在于多個(gè)節(jié)點(diǎn),屬于RabbitMQ的HA方案。
該模式解決了上述問(wèn)題,其實(shí)質(zhì)和普通模式不同之處在于,消息實(shí)體會(huì)主動(dòng)在鏡像節(jié)點(diǎn)間同步,而不是在consumer取數(shù)據(jù)時(shí)臨時(shí)拉取。
該模式帶來(lái)的副作用也很明顯,除了降低系統(tǒng)性能外,如果鏡像隊(duì)列數(shù)量過(guò)多,加之大量的消息進(jìn)入,集群內(nèi)部的網(wǎng)絡(luò)帶寬將會(huì)被這種同步通訊大大消耗掉。
所以在對(duì)可靠性要求較高的場(chǎng)合中適用(后面會(huì)詳細(xì)介紹這種模式,目前我們搭建的環(huán)境屬于該模式)
?
了解集群中的基本概念:
RabbitMQ的集群節(jié)點(diǎn)包括內(nèi)存節(jié)點(diǎn)、磁盤節(jié)點(diǎn)。顧名思義內(nèi)存節(jié)點(diǎn)就是將所有數(shù)據(jù)放在內(nèi)存,磁盤節(jié)點(diǎn)將數(shù)據(jù)放在磁盤。不過(guò),如前文所述,如果在投遞消息時(shí),打開(kāi)了消息的持久化,那么即使是內(nèi)存節(jié)點(diǎn),數(shù)據(jù)還是安全的放在磁盤。
一個(gè)rabbitmq集 群中可以共享 user,vhost,queue,exchange等,所有的數(shù)據(jù)和狀態(tài)都是必須在所有節(jié)點(diǎn)上復(fù)制的,一個(gè)例外是,那些當(dāng)前只屬于創(chuàng)建它的節(jié)點(diǎn)的消息隊(duì)列,盡管它們可見(jiàn)且可被所有節(jié)點(diǎn)讀取。rabbitmq節(jié)點(diǎn)可以動(dòng)態(tài)的加入到集群中,一個(gè)節(jié)點(diǎn)它可以加入到集群中,也可以從集群環(huán)集群會(huì)進(jìn)行一個(gè)基本的負(fù)載均衡。
集群中有兩種節(jié)點(diǎn):
1 內(nèi)存節(jié)點(diǎn):只保存狀態(tài)到內(nèi)存(一個(gè)例外的情況是:持久的queue的持久內(nèi)容將被保存到disk)
2 磁盤節(jié)點(diǎn):保存狀態(tài)到內(nèi)存和磁盤。
內(nèi)存節(jié)點(diǎn)雖然不寫(xiě)入磁盤,但是它執(zhí)行比磁盤節(jié)點(diǎn)要好。集群中,只需要一個(gè)磁盤節(jié)點(diǎn)來(lái)保存狀態(tài) 就足夠了
如果集群中只有內(nèi)存節(jié)點(diǎn),那么不能停止它們,否則所有的狀態(tài),消息等都會(huì)丟失。
?思路:
那么具體如何實(shí)現(xiàn)RabbitMQ高可用,我們先搭建一個(gè)普通集群模式,在這個(gè)模式基礎(chǔ)上再配置鏡像模式實(shí)現(xiàn)高可用,Rabbit集群前增加一個(gè)反向代理,生產(chǎn)者、消費(fèi)者通過(guò)反向代理訪問(wèn)RabbitMQ集群。
架構(gòu)圖如下:圖片來(lái)自http://www.nsbeta.info
上述圖里是3個(gè)RabbitMQ運(yùn)行在同一主機(jī)上,分別用不同的服務(wù)端口。當(dāng)然我們的生產(chǎn)實(shí)際里,多個(gè)RabbitMQ肯定是運(yùn)行在不同的物理服務(wù)器上,否則就失去了高可用的意義。?
?
- 集群模式配置
設(shè)計(jì)架構(gòu)可以如下:在一個(gè)集群里,有4臺(tái)機(jī)器,其中1臺(tái)使用磁盤模式,另2臺(tái)使用內(nèi)存模式。2臺(tái)內(nèi)存模式的節(jié)點(diǎn),無(wú)疑速度更快,因此客戶端(consumer、producer)連接訪問(wèn)它們。而磁盤模式的節(jié)點(diǎn),由于磁盤IO相對(duì)較慢,因此僅作數(shù)據(jù)備份使用,另外一臺(tái)作為反向代理。
四臺(tái)服務(wù)器hostname分別為:queue 、panyuntao1、panyuntao2、panyuntao3(ip:172.16.3.110)
配置RabbitMQ集群非常簡(jiǎn)單,只需要幾個(gè)命令,配置步驟如下:
step1:queue、panyuntao1、panyuntao2做為RabbitMQ集群節(jié)點(diǎn),分別安裝RabbitMq-Server ,安裝后分別啟動(dòng)RabbitMq-server
? ? ? ? ?啟動(dòng)命令 ?# Rabbit-Server start ,安裝過(guò)程及啟動(dòng)命令參見(jiàn):http://www.cnblogs.com/Spinosaurus/p/3944411.html
step2:在安裝好的三臺(tái)節(jié)點(diǎn)服務(wù)器中,分別修改/etc/hosts文件,指定queue、panyuntao1、panyuntao2的hosts,如:
172.16.3.32 queue
172.16.3.107 panyuntao1
172.16.3.108 panyuntao2
還有hostname文件也要正確,分別是queue、panyuntao1、panyuntao2,如果修改hostname建議安裝rabbitmq前修改。
請(qǐng)注意RabbitMQ集群節(jié)點(diǎn)必須在同一個(gè)網(wǎng)段里,如果是跨廣域網(wǎng)效果就差。
step3:設(shè)置每個(gè)節(jié)點(diǎn)Cookie
Rabbitmq的集群是依賴于erlang的集群來(lái)工作的,所以必須先構(gòu)建起erlang的集群環(huán)境。Erlang的集群中各節(jié)點(diǎn)是通過(guò)一個(gè)magic cookie來(lái)實(shí)現(xiàn)的,這個(gè)cookie存放在??/var/lib/rabbitmq/.erlang.cookie?中,文件是400的權(quán)限。所以必須保證各節(jié)點(diǎn)cookie保持一致,否則節(jié)點(diǎn)之間就無(wú)法通信。 -r--------. 1 rabbitmq rabbitmq 20 3月 5 00:00 /var/lib/rabbitmq/.erlang.cookie 將其中一臺(tái)節(jié)點(diǎn)上的.erlang.cookie值復(fù)制下來(lái)保存到其他節(jié)點(diǎn)上。或者使用scp的方法也可,但是要注意文件的權(quán)限和屬主屬組。 我們這里將queue中的cookie 復(fù)制到 panyuntao1、panyuntao2中,先修改下panyuntao1、panyuntao2中的.erlang.cookie權(quán)限 #chmod 777??/var/lib/rabbitmq/.erlang.cookie? 將queue的/var/lib/rabbitmq/.erlang.cookie這個(gè)文件,拷貝到panyuntao1、panyuntao2的同一位置(反過(guò)來(lái)亦可),該文件是集群節(jié)點(diǎn)進(jìn)行通信的驗(yàn)證密鑰,所有節(jié)點(diǎn)必須一致。拷完后重啟下RabbitMQ。 復(fù)制好后別忘記還原.erlang.cookie的權(quán)限,否則可能會(huì)遇到錯(cuò)誤 #chmod 400 /var/lib/rabbitmq/.erlang.cookie? 設(shè)置好cookie后先將三個(gè)節(jié)點(diǎn)的rabbitmq重啟 #?rabbitmqctl stop #?rabbitmq-server start ? step4:停止所有節(jié)點(diǎn)RabbitMq服務(wù),然后使用detached參數(shù)獨(dú)立運(yùn)行,這步很關(guān)鍵,尤其增加節(jié)點(diǎn)停止節(jié)點(diǎn)后再次啟動(dòng)遇到無(wú)法啟動(dòng)都可以參照這個(gè)順序 queue#?rabbitmqctl stop panyuntao1#?rabbitmqctl stop? ? ??panyuntao2#?rabbitmqctl stop ? queue# rabbitmq-server -detached panyuntao1# rabbitmq-server -detached
? ? ??panyuntao2# rabbitmq-server -detached ? 分別查看下每個(gè)節(jié)點(diǎn) queue# rabbitmqctl cluster_status Cluster status of node rabbit@queue ... [{nodes,[{disc,[rabbit@queue]}]},?
{running_nodes,[rabbit@queue]},?
{partitions,[]}]?
...done. ? panyuntao1#?rabbitmqctl cluster_status Cluster status of node rabbit@panyuntao1... [{nodes,[{disc,[rabbit@panyuntao1]}]}, {running_nodes,[rabbit@panyuntao1]}, {partitions,[]}]?
...done. ? ? ??panyuntao2#?rabbitmqctl cluster_status Cluster status of node rabbit@?panyuntao2... [{nodes,[{disc,[rabbit@?panyuntao2]}]}, {running_nodes,[rabbit@?panyuntao2]}, {partitions,[]}]?
...done. ? step4:將panyuntao1、panyuntao2作為內(nèi)存節(jié)點(diǎn)與queue連接起來(lái),在panyuntao1上,執(zhí)行如下命令: ??panyuntao1# rabbitmqctl stop_app panyuntao1# rabbitmqctl join_cluster --ram rabbit@queue ?? panyuntao1# rabbitmqctl start_app
panyuntao2# rabbitmqctl stop_app panyuntao2# rabbitmqctl join_cluster --ram rabbit@queue ??(上方已經(jīng)將panyuntao1與queue連接,也可以直接將panyuntao2與panyuntao1連接,同樣而已加入集群中) panyuntao2# rabbitmqctl start_app 上述命令先停掉rabbitmq應(yīng)用,然后調(diào)用cluster命令,將panyuntao1連接到,使兩者成為一個(gè)集群,最后重啟rabbitmq應(yīng)用。在這個(gè)cluster命令下,panyuntao1、panyuntao2是內(nèi)存節(jié)點(diǎn),queue是磁盤節(jié)點(diǎn)(RabbitMQ啟動(dòng)后,默認(rèn)是磁盤節(jié)點(diǎn))。 queue?如果要使panyuntao1或panyuntao2在集群里也是磁盤節(jié)點(diǎn),join_cluster?命令去掉--ram參數(shù)即可 ?#rabbitmqctl join_cluster rabbit@queue ??
只要在節(jié)點(diǎn)列表里包含了自己,它就成為一個(gè)磁盤節(jié)點(diǎn)。在RabbitMQ集群里,必須至少有一個(gè)磁盤節(jié)點(diǎn)存在。
step5:在queue、panyuntao1、panyuntao2上,運(yùn)行cluster_status命令查看集群狀態(tài):
[root@queue ~]# rabbitmqctl cluster_status?Cluster status of node rabbit@queue ...?
[{nodes,[{disc,[rabbit@queue]},{ram,[rabbit@panyuntao2,rabbit@panyuntao1]}]},?
{running_nodes,[rabbit@panyuntao2,rabbit@panyuntao1,rabbit@queue]},?
{partitions,[]}]?
...done.?
[root@panyuntao1 rabbitmq]# rabbitmqctl cluster_status?
Cluster status of node rabbit@panyuntao1 ...?
[{nodes,[{disc,[rabbit@queue]},{ram,[rabbit@panyuntao2,rabbit@panyuntao1]}]},?
{running_nodes,[rabbit@panyuntao2,rabbit@queue,rabbit@panyuntao1]},?
{partitions,[]}]?
...done. [root@panyuntao2 rabbitmq]# rabbitmqctl cluster_status?
Cluster status of node rabbit@panyuntao2 ...?
[{nodes,[{disc,[rabbit@queue]},{ram,[rabbit@panyuntao2,rabbit@panyuntao1]}]},?
{running_nodes,[rabbit@panyuntao1,rabbit@queue,rabbit@panyuntao2]},?
{partitions,[]}]?
...done. 這時(shí)我們可以看到每個(gè)節(jié)點(diǎn)的集群信息,分別有兩個(gè)內(nèi)存節(jié)點(diǎn)一個(gè)磁盤節(jié)點(diǎn) step6:往任意一臺(tái)集群節(jié)點(diǎn)里寫(xiě)入消息隊(duì)列,會(huì)復(fù)制到另一個(gè)節(jié)點(diǎn)上,我們看到兩個(gè)節(jié)點(diǎn)的消息隊(duì)列數(shù)一致:(如何發(fā)送消息參見(jiàn):?http://www.cnblogs.com/flat_peach/archive/2013/03/04/2943574.html)
root@panyuntao2?:~# rabbitmqctl list_queues -p hrsystem
Listing queues …
test_queue 10000
…done.
test_queue 10000?
…done. root@queue:~# rabbitmqctl list_queues -p hrsystem Listing queues …?
test_queue?10000?
…done. -p參數(shù)為vhost名稱 這樣RabbitMQ集群就正常工作了, ? ? ? ? ?這種模式更適合非持久化隊(duì)列,?只有該隊(duì)列是非持久的,客戶端才能重新連接到集群里的其他節(jié)點(diǎn),并重新創(chuàng)建隊(duì)列。假如該隊(duì)列是持久化的,那么唯一辦法是將故障節(jié)點(diǎn)恢復(fù)起來(lái)。 ? 為什么RabbitMQ不將隊(duì)列復(fù)制到集群里每個(gè)節(jié)點(diǎn)呢?這與它的集群的設(shè)計(jì)本意相沖突,集群的設(shè)計(jì)目的就是增加更多節(jié)點(diǎn)時(shí),能線性的增加性能(CPU、內(nèi)存)和容量(內(nèi)存、磁盤)。理由如下:
1. storage space: If every cluster node had a full copy of every queue, adding nodes wouldn’t give you more storage capacity. For example, if one node could store 1GB of messages, adding two more nodes would simply give you two more copies of the same 1GB of messages.
2. performance: Publishing messages would require replicating those messages to every cluster node. For durable messages that would require triggering disk activity on all nodes for every message. Your network and disk load would increase every time you added a node, keeping the performance of the cluster the same (or possibly worse).
當(dāng)然RabbitMQ新版本集群也支持隊(duì)列復(fù)制(有個(gè)選項(xiàng)可以配置)。比如在有五個(gè)節(jié)點(diǎn)的集群里,可以指定某個(gè)隊(duì)列的內(nèi)容在2個(gè)節(jié)點(diǎn)上進(jìn)行存儲(chǔ),從而在性能與高可用性之間取得一個(gè)平衡。
- 鏡像模式配置
關(guān)于負(fù)載均衡器,商業(yè)的比如F5的BIG-IP,Radware的AppDirector,是硬件架構(gòu)的產(chǎn)品,可以實(shí)現(xiàn)很高的處理能力。但這些產(chǎn)品昂貴的價(jià)格會(huì)讓人止步,所以我們還有軟件負(fù)載均衡方案。互聯(lián)網(wǎng)公司常用的軟件LB一般有LVS、HAProxy、Nginx等。LVS是一個(gè)內(nèi)核層的產(chǎn)品,主要在第四層負(fù)責(zé)數(shù)據(jù)包轉(zhuǎn)發(fā),使用較復(fù)雜。HAProxy和Nginx是應(yīng)用層的產(chǎn)品,但Nginx主要用于處理HTTP,所以這里選擇HAProxy作為RabbitMQ前端的LB。
HAProxy的安裝使用非常簡(jiǎn)單,在Centos下直接yum install haproxy,然后更改/etc/haproxy/haproxy.cfg 文件即可,文件內(nèi)容大概如下:
? ?#--------------------------------------------------------------------- ? ? defaults???? mode??????????????????? http?
??? log???????????????????? global?
??? option????????????????? httplog?
??? option????????????????? dontlognull?
??? option http-server-close?
??? option forwardfor?????? except 127.0.0.0/8?
??? option????????????????? redispatch?
??? retries???????????????? 3?
??? timeout http-request??? 10s?
??? timeout queue?????????? 1m?
??? timeout connect???????? 10s?
??? timeout client????????? 1m?
??? timeout server????????? 1m?
??? timeout http-keep-alive 10s?
??? timeout check?????????? 10s?
??? maxconn???????????????? 3000 ? ? ? listen rabbitmq_cluster 0.0.0.0:5672 ??? mode tcp ??? balance roundrobin ??? server?? rqslave1 172.16.3.107:5672 check inter 2000 rise 2 fall 3 ?? ??? server?? rqslave2 172.16.3.108:5672 check inter 2000 rise 2 fall 3? # ?server?? rqmaster 172.16.3.32:5672 check inter 2000 rise 2 fall 3 ? #--------------------------------------------------------------------- 負(fù)載均衡器會(huì)監(jiān)聽(tīng)5672端口,輪詢我們的兩個(gè)內(nèi)存節(jié)點(diǎn)172.16.3.107、172.16.3.108的5672端口,172.16.3.32為磁盤節(jié)點(diǎn),只做備份不提供給生產(chǎn)者、消費(fèi)者使用,當(dāng)然如果我們服務(wù)器資源充足情況也可以配置多個(gè)磁盤節(jié)點(diǎn) ,這樣磁盤節(jié)點(diǎn)除了故障也不會(huì)影響,除非同時(shí)出故障。 step2:配置策略 ? 使用Rabbit鏡像功能,需要基于rabbitmq策略來(lái)實(shí)現(xiàn),政策是用來(lái)控制和修改群集范圍的某個(gè)vhost隊(duì)列行為和Exchange行為 在cluster中任意節(jié)點(diǎn)啟用策略,策略會(huì)自動(dòng)同步到集群節(jié)點(diǎn) ? # rabbitmqctl set_policy -p hrsystem ha-allqueue"^" '{"ha-mode":"all"}' ? 這行命令在vhost名稱為hrsystem創(chuàng)建了一個(gè)策略,策略名稱為ha-allqueue,策略模式為 all 即復(fù)制到所有節(jié)點(diǎn),包含新增節(jié)點(diǎn), 策略正則表達(dá)式為 “^” 表示所有匹配所有隊(duì)列名稱。 例如rabbitmqctl set_policy -p hrsystem ha-allqueue "^message" '{"ha-mode":"all"}' 注意:"?^message?" 這個(gè)規(guī)則要根據(jù)自己修改,這個(gè)是指同步"message"開(kāi)頭的隊(duì)列名稱,我們配置時(shí)使用的應(yīng)用于所有隊(duì)列,所以表達(dá)式為"^" 官方set_policy說(shuō)明參見(jiàn) set_policy??[-p??vhostpath?] {?name?} {?pattern?} {?definition?} [?priority?] (?http://www.rabbitmq.com/man/rabbitmqctl.1.man.html?) ha-mode:
| all | (absent) | Queue is mirrored across all nodes in the cluster. When a new node is added to the cluster, the queue will be mirrored to that node. |
| exactly | count | Queue is mirrored to?count?nodes in the cluster. If there are less than?count?nodes in the cluster, the queue is mirrored to all nodes. If there are more than?countnodes in the cluster, and a node containing a mirror goes down, then a new mirror will?not?be created on another node. (This is to prevent queues migrating across a cluster as it is brought down.) |
| nodes | node names | Queue is mirrored to the nodes listed in?node names. If any of those node names are not a part of the cluster, this does not constitute an error. If none of the nodes in the list are online at the time when the queue is declared then the queue will be created on the node that the declaring client is connected to. |
參考:
http://www.rabbitmq.com/clustering.html
http://www.rabbitmq.com/ha.html
http://www.rabbitmq.com/parameters.html#policies
http://www.nsbeta.info/archives/555
http://blog.csdn.net/linvo/article/details/7793706
轉(zhuǎn)載于:https://www.cnblogs.com/Spinosaurus/p/3944403.html
總結(jié)
以上是生活随笔為你收集整理的Rabbitmq集群高可用测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 网络编程入门
- 下一篇: 统计找出一千万以内,一共有多少质数