部署高可用RabbitMQ

2020-08-14 11:06:38

安裝

準備工作

這裏我們使用三個RabbitMQ節點:

192.168.7.41 rabbit1
192.168.7.42 rabbit2
192.168.7.43 rabbit3

開通埠(具體見官方文件):

firewall-cmd --zone=public --add-port=4369/tcp --permanent
firewall-cmd --zone=public --add-port=5672-5673/tcp --permanent
firewall-cmd --zone=public --add-port=15692/tcp --permanent
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --zone=public --add-port=25672/tcp --permanent
firewall-cmd --zone=public --add-port=35672-35682/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-port

安裝ErLang和RabbitMQ Server

安裝文件見:https://www.rabbitmq.com/install-rpm.html。

採用RPM包而不是Repo的安裝命令如下(以下的版本號可根據實際情況修改):

# 安裝ErLang
yum install https://bintray.com/rabbitmq-erlang/rpm/download_file\?file_path\=erlang%2F23%2Fel%2F7%2Fx86_64%2Ferlang-23.0.2-1.el7.x86_64.rpm

# 安裝RabbitMQ Server
yum install https://dl.bintray.com/rabbitmq/rpm/rabbitmq-server/v3.8.x/el/7/noarch/rabbitmq-server-3.8.5-1.el7.noarch.rpm

# 啓動服務
systemctl enable rabbitmq-server
systemctl start rabbitmq-server

安裝管理外掛

安裝文件見:https://www.rabbitmq.com/management.html

安裝命令:rabbitmq-plugins enable rabbitmq-management

基本設定

新增使用者

rabbitmqctl add_user admin admin
rabbitmqctl set_user_tags admin administrator

設定叢集與高可用

功能和原理

設計叢集的目的

  • 允許消費者和生產者在RabbitMQ節點崩潰的情況下繼續執行
  • 通過增加更多的節點來擴充套件訊息通訊的吞吐量

叢集設定方式

RabbitMQ可以通過三種方法來部署分佈式集羣系統,分別是:cluster,federation,shovel

  • cluster:
    • 不支援跨網段,用於同一個網段內的區域網
    • 可以隨意的動態增加或者減少
    • 節點之間需要執行相同版本的RabbitMQ和Erlang
  • **federation:**應用於廣域網,允許單台伺服器上的交換機或佇列接收發布到另一臺伺服器上交換機或佇列的訊息,可以是單獨機器或叢集。federation佇列類似於單向對等連線,訊息會在聯盟佇列之間轉發任意次,直到被消費者接受。通常使用federation來連線internet上的中間伺服器,用作訂閱分發訊息或工作佇列。
  • **shovel:**連線方式與federation的連線方式類似,但它工作在更低層次。可以應用於廣域網。

節點型別

  • RAM node:記憶體節點將所有的佇列、交換機、系結、使用者、許可權和vhost的元數據定義儲存在記憶體中,好處是可以使得像交換機和佇列宣告等操作更加的快速。
  • Disk node: 將元數據儲存在磁碟中,單節點系統只允許磁碟型別的節點,防止重新啓動RabbitMQ的時候,丟失系統的設定資訊。

問題說明: RabbitMQ要求在叢集中至少有一個磁碟節點,所有其他節點可以是記憶體節點,當節點加入或者離開叢集時,必須要將該變更通知到至少一個磁碟節點。如果叢集中唯一的一個磁碟節點崩潰的話,叢集仍然可以保持執行,但是無法進行其他操作(增刪改查),直到節點恢復。

**解決方案:**設定兩個磁碟節點,至少有一個是可用的,可以儲存元數據的更改。

Erlang Cookie

Erlang Cookie是保證不同節點可以相互通訊的金鑰,要保證叢集中的不同節點相互通訊必須共用相同的Erlang Cookie。具體的目錄存放在/var/lib/rabbitmq/.erlang.cookie

說明: 這就要從rabbitmqctl命令的工作原理說起,RabbitMQ底層是通過Erlang架構來實現的,所以rabbitmqctl會啓動Erlang節點,並基於Erlang節點來使用Erlang系統連線RabbitMQ節點,在連線過程中需要正確的Erlang Cookie和節點名稱,Erlang節點通過交換Erlang Cookie以獲得認證。

佇列複製

以前對於HA有一種映象佇列(Classic Mirrored Queues),即將佇列內容複製到所有節點。3.8.0版本後,更加推薦Quorum佇列

部署叢集

設定Erlang Cookie

爲了保證這三臺機器的 Erlang cookie 相同,將rabbit1 上面的 Erlang cookie 檔案複製到另外兩臺機器上面。Erlang cookie 檔案的路徑是/var/lib/rabbitmq/.erlang.cookie

如果有$HOME/.erlang.cookie,會優先使用,因此也可以把三個節點的$HOME/.erlang.cookie的內容保持統一。

加入叢集

rabbit1檢視叢集狀態

> rabbitmqctl cluster_status                                                                                                                                     root@rabbit1 15:50:14
Cluster status of node rabbit@rabbit1 ...
Basics

Cluster name: rabbit@rabbit1

Disk Nodes

rabbit@rabbit1

Running Nodes

rabbit@rabbit1

Versions

rabbit@rabbit1: RabbitMQ 3.8.5 on Erlang 23.0.2

...

其中,Cluster name: rabbit@rabbit1,這是叢集名字,其他節點可以加入這個叢集中。

對其他兩個節點停止RabbitMQ服務,然後執行加入叢集命令:

# 停止RabbitMQ
rabbitmqctl stop_app
# 加入叢集
rabbitmqctl join_cluster rabbit@rabbit1
# 啓動RabbitMQ
rabbitmqctl start_app

在任意節點檢視叢集狀態:

> rabbitmqctl cluster_status                                                                                                                                     root@rabbit3 16:01:55
Cluster status of node rabbit@rabbit3 ...
Basics

Cluster name: rabbit@rabbit1

Disk Nodes

rabbit@rabbit1
rabbit@rabbit2
rabbit@rabbit3

Running Nodes

rabbit@rabbit1
rabbit@rabbit2
rabbit@rabbit3

Versions

rabbit@rabbit1: RabbitMQ 3.8.5 on Erlang 23.0.2
rabbit@rabbit2: RabbitMQ 3.8.5 on Erlang 23.0.2
rabbit@rabbit3: RabbitMQ 3.8.5 on Erlang 23.0.2

可以看到三個節點已經構建成了一個叢集,但是有一個小問題,所有的節點都是磁碟節點,我們並不需要所有節點都是磁碟節點。假設這裏需要rabbit@rabbit1爲磁碟節點,另外兩個都是記憶體節點,這樣我們在保證可用性的同時,還能提高叢集的整體效能。

下面 下麪將兩臺磁碟節點改成記憶體節點。

移除節點

對於rabbit2rabbit3進行如下操作:

rabbitmqctl stop_app
rabbitmqctl reset

這裏關鍵的命令是 rabbitmqctl reset。reset 命令在節點爲單機狀態和是叢集的一部分時行爲有點不太一樣。

節點單機狀態時,reset 命令將清空節點的狀態,並將其恢復到空白狀態。當節點是叢集的一部分時,該命令也會和叢集中的磁碟節點通訊,告訴他們該節點正在離開叢集。

這很重要,不然,叢集會認爲該節點出了故障,並期望其最終能夠恢復回來,在該節點回來之前,叢集禁止新的節點加入。

作爲記憶體節點加入叢集

對其他兩個節點停止RabbitMQ服務,然後執行加入叢集命令:

# 停止RabbitMQ
rabbitmqctl stop_app
# 加入叢集
rabbitmqctl join_cluster --ram rabbit@rabbit1
# 啓動RabbitMQ
rabbitmqctl start_app

設定高可用

HAProxy

首先安裝HAProxy:

yum install -y 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

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         2s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           1s
    maxconn                 3000

#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------

frontend  rabbitmq_15672
    bind              0.0.0.0:15672
    mode              http
    log               global
    option            httplog
    option forwardfor except 127.0.0.0/8
    default_backend   rabbitmq_management


#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------

backend rabbitmq_management
    balance     roundrobin
    server      rabbit1 192.168.7.41:15672 check
    server      rabbit2 192.168.7.42:15672 check
    server      rabbit3 192.168.7.43:15672 check
    
listen rabbitcluster 0.0.0.0:5672
    mode tcp
    option tcplog
    timeout client  3h
    timeout server  3h
    server rabbit1 192.168.7.41:5672 check fall 3 rise 2
    server rabbit1 192.168.7.42:5672 check fall 3 rise 2
    server rabbit1 192.168.7.43:5672 check fall 3 rise 2

KeepAlived

利用keepalived設定高可用。

安裝keepalived:

yum install keepalived
# 備份組態檔
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak

編輯組態檔/etc/keepalived/keepalived.conf

# MASTER節點
global_defs {
   router_id MYSQL_ROUTER					# 各節點統一ID
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_script check_mysqlrouter {
    script "ps -C haproxy | grep haproxy"	# 檢測HAProxy是否在執行
    interval 2
    weight 2
    fall 2
}

vrrp_instance VI_1 {
    state MASTER					# 主節點
    interface ens192			# VIP系結的網絡卡
    virtual_router_id 33	# 各節點統一的虛擬ID
    priority 102					# 數越高優先順序越高
    advert_int 1					# 檢測間隔 1s
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.7.33			# VIP
    }
    track_script {
        check_mysqlrouter	# 檢測指令碼
    }
}

# BACKUP節點(不同的設定)
    state BACKUP					# 備節點
    priority 101					# 數值低於MASTER

設定防火牆:

firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload

重新啓動keepalived:systemctl restart keepalived,然後ip a檢視VIP系結情況。

Quorum佇列

叢集實現高可用之後,佇列也要設定爲多節點才行,目前官方文件推薦設定爲Quorum Queue。佇列只能在用戶端建立的時候設定爲Quorum。

  1. 在RabbitMQ管理介面建立的時候,下拉框選擇「Quorum」:

效果如下:

  1. 程式設計方面以Java爲例,建立Queue的時候需要指定x-queue-type參數:
Map<String, Object> args = new HashMap<>();
// // set the queue with a dead letter feature
args.put("x-queue-type", "queue");
return new Queue(MY_QUEUE_NAME, NON_DURABLE, false, false, args);