本文介紹 RabbitMQ 集群的 Docker 化部署,最開始是想通過(guò) DockerSwarm 方式來(lái)部署的,但是 RabbitMQ 節(jié)點(diǎn)加入集群時(shí)一直失敗,在網(wǎng)上找了很多辦法,始終沒有解決這個(gè)問題,無(wú)奈只能放棄。所以最終采用配置 hosts 文件方式來(lái)保證節(jié)點(diǎn)之間的通信,下面來(lái)進(jìn)行詳細(xì)說(shuō)明。
部署環(huán)境
- 系統(tǒng):CentOS8
- 兩臺(tái)服務(wù)器:10.1.1.1/10.1.1.2
docker-compose 文件
version: '3'
services:
rabbit1:
container_name: rabbit1
image: rabbitmq:3.7-management-alpine
restart: always
hostname: rabbit1
extra_hosts:
- "rabbit1:10.1.1.1"
- "rabbit2:10.1.1.2"
environment:
- RABBITMQ_ERLANG_COOKIE=MY_COOKIE
- RABBITMQ_DEFAULT_USER=MY_USER
- RABBITMQ_DEFAULT_PASS=MY_PASS
ports:
- "4369:4369"
- "5671:5671"
- "5672:5672"
- "15671:15671"
- "15672:15672"
- "25672:25672"
這樣,10.1.1.1 上的 docker-compose 文件就寫好了,部署另一臺(tái)時(shí),只要將 rabbit1 改成 rabbit2 就可以了。如果是更多臺(tái)服務(wù)器的話,也是同樣的道理,將 IP 配置到 extra_hosts 參數(shù)下即可。
啟動(dòng)服務(wù)
在兩臺(tái)服務(wù)器上分別執(zhí)行:
# docker-compose up -d
加入集群
如果將 rabbit1 作為主節(jié)點(diǎn)的話,需要在 rabbit2 上執(zhí)行命令,將其加入到集群,如下:
# docker exec -it rabbit2 /bin/bash
rabbit2# rabbitmqctl stop_app
rabbit2# rabbitmqctl reset
rabbit2# rabbitmqctl join_cluster rabbit@rabbit1
rabbit2# rabbitmqctl start_app
默認(rèn)情況下,RabbitMQ 啟動(dòng)后是磁盤節(jié)點(diǎn),如果想以內(nèi)存節(jié)點(diǎn)方式加入,可以加 --ram 參數(shù)。
如果想要修改節(jié)點(diǎn)類型,可以使用命令:
# rabbitmqctl change_cluster_node_type disc(ram)
修改節(jié)點(diǎn)類型之前需要先 rabbitmqctl stop_app。
通過(guò)下面命令來(lái)查看集群狀態(tài):
# rabbitmqctl cluster_status
注意,由于 RAM 節(jié)點(diǎn)僅將內(nèi)部數(shù)據(jù)庫(kù)表存儲(chǔ)在內(nèi)存中,因此在內(nèi)存節(jié)點(diǎn)啟動(dòng)時(shí)必須從其他節(jié)點(diǎn)同步這些數(shù)據(jù),所以一個(gè)集群必須至少包含一個(gè)磁盤節(jié)點(diǎn)。
HAProxy 負(fù)載均衡
ha 同樣采用 Docker 方式來(lái)部署,先看一下 haproxy.cfg 配置文件:
# Simple configuration for an HTTP proxy listening on port 80 on all
# interfaces and forwarding requests to a single backend "servers" with a
# single server "server1" listening on 127.0.0.1:8000
global
daemon
maxconn 256
defaults
mode http
timeout connect 5000ms
timeout client 5000ms
timeout server 5000ms
listen rabbitmq_cluster
bind 0.0.0.0:5677
option tcplog
mode tcp
balance leastconn
server rabbit1 10.1.1.1:5672 weight 1 check inter 2s rise 2 fall 3
server rabbit2 10.2.2.2:5672 weight 1 check inter 2s rise 2 fall 3
listen http_front
bind 0.0.0.0:8002
stats uri /haproxy?stats
listen rabbitmq_admin
bind 0.0.0.0:8001
server rabbit1 10.1.1.1:15672
server rabbit2 10.1.1.2:15672
再看一下 docker-compose 文件:
version: '3'
services:
haproxy:
container_name: rabbit-haproxy
image: haproxy
restart: always
hostname: haproxy
network_mode: rabbitmq_default
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
ports:
- "5677:5677"
- "8001:8001"
- "8002:8002"
啟動(dòng)之后,就可以通過(guò) ha 的地址來(lái)訪問 RabbitMQ 集群管理頁(yè)面了。
如果公司內(nèi)部有現(xiàn)成的負(fù)載均衡,比如 LVS,那么也可以省略這一步。
其實(shí)到這里,集群就可以正常使用了,但還有很重要的一點(diǎn)需要做些說(shuō)明。
集群模式
普通模式
- 對(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)的隊(duì)列中后,消費(fèi)者從 B 節(jié)點(diǎn)拉取時(shí),RabbitMQ 會(huì)臨時(shí)在 A、B 間進(jìn)行消息傳輸,把 A 中的消息實(shí)體取出并經(jīng)過(guò) B 發(fā)送給消費(fèi)者。
- 所以,消費(fèi)者應(yīng)盡量連接每一個(gè)節(jié)點(diǎn),從中取消息。即對(duì)于同一個(gè)邏輯隊(duì)列,要在多個(gè)節(jié)點(diǎn)建立物理隊(duì)列,否則,無(wú)論消費(fèi)者連 A 或者連 B,出口總在 A,會(huì)產(chǎn)生瓶頸。
- 該模式還存在一個(gè)問題就是當(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);如果沒有持久化的話,消息會(huì)丟失。
鏡像模式
- 該模式解決了上述問題,其和普通模式不同之處在于,消息實(shí)體會(huì)主動(dòng)在鏡像節(jié)點(diǎn)間同步,而不是在消費(fèi)者取數(shù)據(jù)時(shí)臨時(shí)拉取。
- 該模式帶來(lái)的副作用也很明顯,除了降低系統(tǒng)性能外,如果鏡像隊(duì)列數(shù)量過(guò)多,加之大量的消息進(jìn)入,集群內(nèi)部的網(wǎng)絡(luò)帶寬將會(huì)被這種同步通訊大大消耗掉。
- 所以,在對(duì)可靠性要求較高的場(chǎng)合中適用于該模式。
個(gè)人感覺,在生產(chǎn)環(huán)境中,還是使用鏡像模式比較保險(xiǎn)。
要想使用鏡像模式,不管是通過(guò)管理頁(yè)面,還是命令行方式,只需要簡(jiǎn)單配置即可完成。管理頁(yè)面方式就不過(guò)多介紹了,下面說(shuō)說(shuō)如何通過(guò)命令行來(lái)設(shè)置,一條命令就搞定。
添加:
# rabbitmqctl set_policy -p testvhost testha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
Setting policy "testha" for pattern "^" to "{"ha-mode":"all","ha-sync-mode":"automatic"}" with priority "0" for vhost "testvhost" ...
清除:
# rabbitmqctl clear_policy -p testvhost testha
Clearing policy "testha" on vhost "testvhost" ...
查看:
# rabbitmqctl list_policies -p testvhost
Listing policies for vhost "testvhost" ...
vhost name pattern apply-to definition priority
testvhost testha ^ all {"ha-mode":"all","ha-sync-mode":"automatic"} 0
參數(shù)說(shuō)明:
Virtual host:策略應(yīng)用的 vhost。
Name:為策略名稱,可以是任何名稱,但建議使用不帶空格的基于 ASCII 的名稱。
Pattern:與一個(gè)或多個(gè) queue(exchange) 名稱匹配的正則表達(dá)式,可以使用任何正則表達(dá)式。只有一個(gè)
^代表匹配所有,^test為匹配名稱為 "test" 的 exchanges 或者 queue。Apply to:Pattern 應(yīng)用對(duì)象。
Priority:配置多個(gè)策略時(shí)的優(yōu)先級(jí),值越大,優(yōu)先級(jí)越高。沒有指定優(yōu)先級(jí)的消息會(huì)以 0 優(yōu)先級(jí)對(duì)待,對(duì)于超過(guò)隊(duì)列所定最大優(yōu)先級(jí)的消息,優(yōu)先級(jí)以最大優(yōu)先級(jí)對(duì)待。
-
Definition:鍵/值對(duì),將被插入匹配 queues and exchanges 的可選參數(shù)映射中。
ha-mode:策略鍵,分為 3 種模式:-
all:所有的 queue。 -
exctly:部分(需配置ha-params參數(shù),此參數(shù)為 int 類型。比如 3,眾多集群中的隨機(jī) 3 臺(tái)機(jī)器)。 -
nodes:指定(需配置ha-params參數(shù),此參數(shù)為數(shù)組類型。比如 ["rabbit@rabbit2", "rabbit@rabbit3"] 這樣指定為 rabbit2 與 rabbit3 這兩臺(tái)機(jī)器)。
ha-sync-mode:隊(duì)列同步:-
manual:手動(dòng)(默認(rèn)模式)。新的隊(duì)列鏡像將不會(huì)收到現(xiàn)有的消息,它只會(huì)接收新的消息。 -
automatic:自動(dòng)同步。當(dāng)一個(gè)新鏡像加入時(shí),隊(duì)列會(huì)自動(dòng)同步。隊(duì)列同步是一個(gè)阻塞操作。
-
以上就是本篇全部?jī)?nèi)容,歡迎大家留言交流。