Linux 部署 RabbitMQ 集羣

通常狀況下,若是隻是爲了探究 RabbitMQ 或者驗證業務工程的正確性那麼在本地環境或者測試環境上使用其單實例部署就能夠了,可是出於 MQ 中間件自己的可靠性、併發性、吞吐量和消息堆積能力等問題的考慮,在生產環境上通常都會考慮使用 RabbitMQ 的集羣方案。node

本文檔旨在介紹 RabbitMQ 集羣的工做原理以及在 CentOS 7 系統上安裝配置具有高可用性和具有必定負載能力的 RabbitMQ 集羣。linux

RabbitMQ 集羣工做原理介紹

RabbitMQ 這款消息隊列中間件產品自己是基於 Erlang 編寫,Erlang 語言天生具有分佈式特性(經過同步 Erlang 集羣各節點的 magic cookie 來實現)。所以,RabbitMQ 自然支持 Clustering。這使得 RabbitMQ 自己不須要像ActiveMQ、Kafka 那樣經過 ZooKeeper 分別來實現 HA 方案和保存集羣的元數據。集羣是保證可靠性的一種方式,同時能夠經過水平擴展以達到增長消息吞吐量能力的目的。git

RabbitMQ 集羣有兩種模式:github

  • 默認模式,以兩個節點 mq1 和 mq2 爲例來進行說明。對於 Queue 來講,消息實體只存在於其中一個節點 mq1 或者 mq2 ,mq1 和 mq2 兩個節點僅有相同的元數據,即隊列的結構。當消息進入 mq1 節點的 Queue 後,consumer 從 mq2 節點消費時,RabbitMQ 會臨時在 mq1 、mq2 間進行消息傳輸,把 A 中的消息實體取出並通過 B 發送給 consumer。因此 consumer 應儘可能鏈接每個節點,從中取消息。即對於同一個邏輯隊列,要在多個節點創建物理 Queue。不然不管 consumer 連 mq1 或 mq2 ,出口總在 mq1,會產生瓶頸。當 mq1 節點故障後,mq2 節點沒法取到 mq1 節點中還未消費的消息實體。若是作了消息持久化,那麼得等 mq1 節點恢復,而後纔可被消費;若是沒有持久化的話,就會產生消息丟失的現象。
  • 鏡像模式,把須要的隊列作成鏡像隊列,存在與多個節點屬於RabbitMQ 的 HA 方案。該模式解決了普通模式中的問題,其實質和普通模式不一樣之處在於,消息實體會主動在鏡像節點間同步,而不是在客戶端取數據時臨時拉取。該模式帶來的反作用也很明顯,除了下降系統性能外,若是鏡像隊列數量過多,加之大量的消息進入,集羣內部的網絡帶寬將會被這種同步通信大大消耗掉。因此在對可靠性要求較高的場合中適用。

RabbitMQ 集羣部署

RabbitMQ 集羣主機環境以下:bash

mq-node1(master)  10.200.100.231 master.yeaheo.com
mq-node2(node01)  10.200.100.231 node01.yeaheo.com
mq-node3(node02)  10.200.100.231 node02.yeaheo.com

各主機系統環境及 MQ 版本以下:cookie

$ cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)

$ uname -r
3.10.0-862.el7.x86_64

Erlang : 21.1
RabbitMQ: v3.7.9

修改各主機 hosts 文件以下:網絡

....
10.200.100.231 master master.yeaheo.com
10.200.100.217 node01 node01.yeaheo.com
10.200.100.218 node02 node02.yeaheo.com
....

配置 RabbitMQ 集羣首先須要在各個主機上安裝並配置 Erlang 和 RabbitMQ ,Erlang安裝過程能夠參考: rabbitmq-erlang-installation.md RabbitMQ 具體過程能夠參考:rabbitmq-single-installation.md併發

當 Erlang 和 RabbitMQ 安裝完成後就能夠配置 RabbitMQ 集羣了。app

配置 RabbitMQ 集羣

本次部署集羣時都是將其餘兩個 RabbitMQ 加入到 master 主機現有集羣中。socket

rabbitmq-server 啓動時,會一塊兒啓動節點和應用,它預先設置 RabbitMQ 應用爲 standalone 模式。要將一個節點加入到現有的集羣中,你須要中止這個應用,並將節點設置爲原始狀態。若是使用 rabbitmqctl stop,應用和節點都將被關閉。因此使用 rabbitmqctl stop_app僅僅關閉應用

同步集羣 cookie

RabbitMQ 利用 erlang 的分佈式特性組建集羣,erlang 集羣經過 magic cookie 實現,此 cookie 保存在$home/.erlang.cookie,這裏即:/var/lib/rabbitmq/.erlang.cookie,須要保證集羣各節點的此 cookie 一致,能夠選取一個節點的 cookie,採用 scp 同步到其餘節點:

$ scp /var/lib/rabbitmq/.erlang.cookie root@node01:/var/lib/rabbitmq/.erlang.cookie
$ scp /var/lib/rabbitmq/.erlang.cookie root@node02:/var/lib/rabbitmq/.erlang.cookie

更換 cookie 後須要重啓 RabbitMQ 服務:

$ systemctl stop rabbitmq-server.service
$ systemctl start rabbitmq-server.service

切換 RabbitMQ 啓動方式

全部節點須要使用 -detached 參數啓動服務:

# 須要在全部節點上執行
$ rabbitmqctl stop
$ rabbitmq-server -detached

組建 RabbitMQ 集羣

由於將其餘兩個 RabbitMQ 加入到 master 主機現有集羣中,因此只須要在 node01node02 上操做便可:

node01 主機(10.200.100.217)上操做:

node01$ rabbitmqctl stop_app
node01$ rabbitmqctl join_cluster rabbit@master         ####這裏集羣的名字必定不要寫錯了
node01$ rabbitmqctl start_app
集羣名字通常能夠在 master主機的日誌文件中看到,須要注意的是這個集羣名字須要和日誌文件中保持一致,不然加入集羣時會報錯

node02 主機(10.200.100.218)上操做:

node02$ rabbitmqctl stop_app
node02$ rabbitmqctl join_cluster rabbit@master         ####這裏集羣的名字必定不要寫錯了
node02$ rabbitmqctl start_app

查看集羣狀態:

$ rabbitmqctl cluster_status
Cluster status of node rabbit@master ...
[{nodes,[{disc,[rabbit@master,rabbit@node01]},{ram,[rabbit@node02]}]},
 {running_nodes,[rabbit@node02,rabbit@node01,rabbit@master]},
 {cluster_name,<<"rabbit@master">>},
 {partitions,[]},
 {alarms,[{rabbit@node02,[]},{rabbit@node01,[]},{rabbit@master,[]}]}]

此時 node01node02 也會自動創建鏈接,集羣配置完成。

若是要使用內存節點,則可使用 rabbitmqctl join_cluster --ram rabbit@master 加入集羣。

RabbitMQ 節點分爲內存節點和磁盤節點:

1)內存節點(RAM):內存節點將全部的隊列、交換機、綁定、用戶、權限和vhost的元數據定義存儲在內存中
2)磁盤節點(Disk):將元數據存儲在磁盤中,單節點系統只容許磁盤類型的節點,防止重啓RabbitMQ的時候,丟失系統的配置信息。

若是須要切換節點類型,能夠參考以下命令:

#若是節點已經是"disk"節點,能夠修改成內存節點
$ rabbitmqctl stop_app
$ rabbitmqctl change_cluster_node_type ram
$ rabbitmqctl start_app
1)RabbitMQ要求在集羣中至少有一個磁盤節點,全部其餘節點能夠是內存節點,當節點加入或者離開集羣時,必需要將該變動通知到至少一個磁盤節點。若是集羣中惟一的一個磁盤節點崩潰的話,集羣仍然能夠保持運行,可是沒法進行其餘操做(增刪改查),直到節點恢復, 或者能夠設置兩個磁盤節點,以保持有一個是可用的。
2)內存節點雖然不寫入磁盤,可是它執行比磁盤節點要好。
3)若是集羣中只有內存節點,那麼不能中止它們,不然全部的狀態,消息等都會丟失。

設置鏡像隊列策略

通過上述配置,集羣雖然搭建成功,但只是默認的普通集羣,exchange,binding 等數據能夠複製到集羣各節點。
但對於隊列來講,各節點只有相同的元數據,即隊列結構,但隊列實體只存在於建立改隊列的節點,即隊列內容不會複製(從其他節點讀取,能夠創建臨時的通訊傳輸)。這樣此節點宕機後,其他節點沒法從宕機節點獲取還未消費的消息實體。若是作了持久化,則須要等待宕機節點恢復,期間其他節點不能建立宕機節點已建立過的持久化隊列;若是未作持久化,則消息丟失。

下邊來配置策略,策略名稱爲 ha-all,通配符 ^ 表示匹配到的全部隊列,複製到全部節點,在任一節點上執行:

$ rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'

也能夠複製匹配到的隊列到集羣中的任意兩個或多個節點,而不是到全部節點,並進行自動同步:

$ rabbitmqctl set_policy ha-all "^" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'

或者複製匹配到的隊列到集羣中的指定節點:

$ rabbitmqctl set_policy ha-all "^" '{"ha-mode":"nodes","ha-params":["rabbit@node01","rabbit@node02"]}'

至此,鏡像隊列策略配置完成,同時也實現了 HA。

HAProxy 配置

咱們在10.200.100.218主機上直接用 yum 安裝 HAProxy 便可:

$ yum -y install haproxy

修改 HAProxy 配置文件 /etc/haproxy/haproxy.cfg以下:

global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    stats socket /var/lib/haproxy/stats

defaults
    mode                    tcp
    log                     global
    option                  tcplog
    option                  dontlognull
    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:5670
    mode tcp
    balance roundrobin
    server node1 10.200.100.217:5672 check inter 2000 rise 2 fall 3
    server node2 10.200.100.218:5672 check inter 2000 rise 2 fall 3
    server node3 10.200.100.231:5672 check inter 2000 rise 2 fall 3

listen monitor 0.0.0.0:8100
    mode http
    option httplog
    stats enable
    stats uri /stats
    stats refresh 5s

重啓 HAProxy:

$ systemctl restart haproxy.service

以後就能夠經過 http://10.200.100.218:8100/stats 查看 HAProxy 的狀態了。

若是用的是雲主機,能夠利用雲服務商本身的 LB,不必定要用 HAProxy
相關文章
相關標籤/搜索