RabbitMQ分佈式集群架構和高可用性(HA)



(一) 功能和原理

設計集群的目的
  • 允許消費者和生產者在RabbitMQ節點崩潰的情況下繼續運行
  • 通過增加更多的節點來擴展消息通信的吞吐量

1 集群配置方式

RabbitMQ可以通過三種方法來部署分佈式集群系統,分別是:cluster,federation,shovel
  • cluster:
    • 不支持跨網段,用於同一個網段內的局域網
    • 可以隨意的動態增加或者減少
    • 節點之間需要運行相同版本的RabbitMQ和Erlang
  • federation:應用於廣域網,允許單台服務器上的交換機或隊列接收發佈到另一台服務器上交換機或隊列的消息,可以是單獨機器或集群。federation隊列類似於單向點對點連接,消息會在聯盟隊列之間轉發任意次,直到被消費者接受。通常使用federation來連接internet上的中間服務器,用作訂閱分發消息或工作隊列。
  • shovel:連接方式與federation的連接方式類似,但它工作在更低層次。可以應用於廣域網。

2 節點類型

  • RAM node:內存節點將所有的隊列、交換機、綁定、用戶、權限和vhost的元數據定義存儲在內存中,好處是可以使得像交換機和隊列聲明等操作更加的快速。
  • Disk node:將元數據存儲在磁盤中,單節點系統只允許磁盤類型的節點,防止重啟RabbitMQ的時候,丟失系統的配置信息。
問題說明: RabbitMQ要求在集群中至少有一個磁盤節點,所有其他節點可以是內存節點,當節點加入或者離開集群時,必須要將該變更通知到至少一個磁盤節點。如果集群中唯一的一個磁盤節點崩潰的話,集群仍然可以保持運行,但是無法進行其他操作(增刪改查),直到節點恢復。
解決方案:設置兩個磁盤節點,至少有一個是可用的,可以保存元數據的更改。

3 Erlang Cookie

Erlang Cookie是保證不同節點可以相互通信的密鑰,要保證集群中的不同節點相互通信必須共享相同的Erlang Cookie。具體的目錄存放在/var/lib/rabbitmq/.erlang.cookie。
說明:這就要從rabbitmqctl命令的工作原理說起,RabbitMQ底層是通過Erlang架構來實現的,所以rabbitmqctl會啟動Erlang節點,並基於Erlang節點來使用Erlang系統連接RabbitMQ節點,在連接過程中需要正確的Erlang Cookie和節點名稱,Erlang節點通過交換Erlang Cookie以獲得認證。

4 鏡像隊列

功能和原理 RabbitMQ的Cluster集群模式一般分為兩種,普通模式和鏡像模式。
  • 普通模式:默認的集群模式,以兩個節點(rabbit01、rabbit02)為例來進行說明。對於Queue來說,消息實體只存在於其中一個節點rabbit01(或者rabbit02),rabbit01和rabbit02兩個節點僅有相同的元數據,即隊列的結構。當消息進入rabbit01節點的Queue後,consumer從rabbit02節點消費時,RabbitMQ會臨時在rabbit01、rabbit02間進行消息傳輸,把A中的消息實體取出並經過B發送給consumer。所以consumer應盡量連接每一個節點,從中取消息。即對於同一個邏輯隊列,要在多個節點建立物理Queue。否則無論consumer連rabbit01或rabbit02,出口總在rabbit01,會產生瓶頸。當rabbit01節點故障後,rabbit02節點無法取到rabbit01節點中還未消費的消息實體。如果做了消息持久化,那麼得等rabbit01節點恢復,然後才可被消費;如果沒有持久化的話,就會產生消息丟失的現象。

下面表示在集群配置下的不同節點創建隊列的情況


下圖表示在集群配置下的不同節點創建交換器和隊列的綁定的情況

鏡像模式:將需要消費的隊列變為鏡像隊列,存在於多個節點,這樣就可以實現RabbitMQ的HA高可用性。作用就是消息實體會主動在鏡像節點之間實現同步,而不是像普通模式那樣,在consumer消費數據時臨時讀取。缺點就是,集群內部的同步通訊會佔用大量的網絡帶寬。


實現機制 鏡像隊列實現了RabbitMQ的高可用性(HA),具體的實現策略如下所示:
ha-mode ha-params 功能
all 鏡像隊列將會在整個集群中復制。當一個新的節點加入後,也會在這個節點上複製一份。
exactly count 鏡像隊列將會在集群上複製count份。如果集群數量少於count時候,隊列會復製到所有節點上。如果大於Count集群,有一個節點crash後,新進入節點也不會做新的鏡像。
nodes node name 鏡像隊列會在node name中復制。如果這個名稱不是集群中的一個,這不會觸發錯誤。如果在這個node list中沒有一個節點在線,那麼這個queue會被聲明在client連接的節點。

實例列舉:
1 
2
queue_args("x-ha-policy":"all") //定义字典来设置额外的队列声明参数
channel.queue_declare(queue="hello-queue",argument=queue_args)
如果需要設定特定的節點(以rabbit@localhost為例),再添加一個參數
1 
2 
3
queue_args("x-ha-policy":"nodes",
           "x-ha-policy-params":["rabbit@localhost"])
channel.queue_declare(queue="hello-queue",argument=queue_args)

可以通過命令行查看那個主節點進行了同步
1
rabbitmqctl list_queue name slave_pids synchronised_slave_pids

(二) RabbitMQ Cluster 配置

1 單機多節點部署

在啟動RabbitMQ節點之後,服務器默認的節點名稱是Rabbit和監聽端口5672,如果想在同一台機器上啟動多個節點,那麼其他的節點就會因為節點名稱和端口與默認的衝突而導致啟動失敗,可以通過設置環境變量來實現,具體方法如下:
  • 首先在機器上設置兩個節點rabbit和rabbit_01
1 
2 
3 
4 
5
rabbitmqctl stop //先停止运行节点,再进行集群部署
RABBITMQ_NODE_PORT=5672 RABBITMQ_NODENAME=rabbit //设置环境变量指定端口和节点名称
rabbitmq-server -detached //后台启动节点
RABBITMQ_NODE_PORT=5673 RABBITMQ_NODENAME=rabbit_01 //设置环境变量指定端口和节点名称
rabbitmq-server -detached //后台启动节点
或者通過添加/etc/rabbitmq/rabbitmq-env.conf文件來進行設置:
1 
2 
3 
4
NODE_PORT=5672
NODENAME=rabbit
NODE_PORT=5673
NODENAME=rabbit_01
  • 將rabbit_01節點添加到第一個集群節點rabbit中
1 
2 
3 
4
rabbitmqctl -n rabbit_01@localhost stop_app //停止rabbit_01节点的应用
rabbitmqctl -n rabbit_01@localhost join_cluster rabbit@localhost //将rabbit_01添加到集群节点rabbit中去
rabbitmqctl cluster_status //查看集群节点的状态
rabbitmqctl -n rabbit_01@localhost start_app //启动rabbit_01节点的应用
1 
2 
3 
4 
5 
6 
7
//可以看到如下信息,说明节点添加成功,表明都是磁盘类型的节点
Cluster status of node rabbit@localhost ...
[{nodes,[{disc,[rabbit@localhost,rabbit_01@localhost]}]},
 {running_nodes,[rabbit@localhost]},
 {cluster_name,<<"rabbit@localhost">>},
 {partitions,[]},
 {alarms,[{rabbit@localhost,[]}]}]

2 多機多節點部署

不同於單機多節點的情況,在多機環境,如果要在cluster集群內部署多個節點,需要注意兩個方面:
  • 保證需要部署的這幾個節點在同一個局域網內
  • 需要有相同的Erlang Cookie,否則不能進行通信,為保證cookie的完全一致,採用從一個節點copy的方式
環境介紹
RabbitMQ節點 IP地址 工作模式 操作系統
rabbitmqCluster 192.168.118.133 DISK CentOS 7.0 - 64位
rabbitmqCluster01 192.168.118.134 DISK CentOS 7.0 - 64位
rabbitmqCluster02 192.168.118.135 DISK CentOS 7.0 - 64位



cluster部署過程
  • 局域網配置 分別在三個節點的/etc/hosts下設置相同的配置信息
1 
2 
3
  192.168.118.133 rabbitmqCluster
  192.168.118.134 rabbitmqCluster01
  192.168.118.135 rabbitmqCluster02
  • 設置不同節點間同一認證的Erlang Cookie 採用從主節點copy的方式保持Cookie的一致性
1 
2
[root@rabbitmqCluster01]# scp /var/lib/rabbitmq/.erlang.cookie 192.168.118.134:/var/lib/rabbitmq
[root@rabbitmqCluster02]# scp /var/lib/rabbitmq/.erlang.cookie 192.168.118.135:/var/lib/rabbitmq
  • 使用-detached運行各節點
1 
2
rabbitmqctl stop
rabbitmq-server -detached 
  • 查看各節點的狀態
1 
2 
3
[root@rabbitmqCluster]#rabbitmqctl cluster_status
[root@rabbitmqCluster01]#rabbitmqctl cluster_status
[root@rabbitmqCluster02]#rabbitmqctl cluster_status
  • 創建並部署集群,以rabbitmqCluster01節點為例:
1 
2 
3
[root@rabbitmqCluster01]#rabbitmqctl stop_app
[root@rabbitmqCluster01]#rabbitmqctl join_cluster rabbit@rabbitmqCluster
[root@rabbitmqCluster01]#rabbitmqctl start_app
  • 查看集群狀態
1
[root@rabbitmqCluster]#rabbitmqctl cluster_status

RabbitMQ負載均衡配置

前言:從目前來看,基於RabbitMQ的分佈式通信框架主要包括兩部分內容,一是要確保可用性和性能,另一個就是編寫當節點發生故障時知道如何重連到集群的應用程序。負載均衡就是解決處理節點的選擇問題。

安裝HAProxy

選擇開源的HAProxy為RabbitMQ集群做負載均衡器,在CentOS 7.0中安裝HAProxy。
  • 安裝epel
1
rpm -ivh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-5.noarch.rpm//
  • 安裝HAProxy
1
yum -y install haproxy
  • 配置HAProxy
1 
2
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
vim /etc/haproxy/haproxy.cfg
  • 添加配置信息
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11
listen rabbitmq_local_cluster 127.0.0.1:5670 //前段IP,供product和consumer来进行选择,由于5672端口已经默认使用,这里选择5670端口
     mode tcp   //负载均衡选项
     balance roundrobin //轮询算法将负载发给后台服务器
     server rabbit 127.0.0.1:5672 check inter 5000 rise 2 fall 3//负载均衡中的集群节点配置,这里选择的rabbit节点
  
  listen private_monitoring :8100
     mode http
     option httplog
     stats enable
     stats uri       /stats
     stats refresh 60s
  • 設置開機啟動
1 
2
chkconfig haproxy on
service haproxy start
  • 訪問localhost:8100/stats就可以看到具體的控制界面。

留言

這個網誌中的熱門文章

Json概述以及python對json的相關操作

Docker容器日誌查看與清理

遠程控制管理工具ipmitool