快速搭建高可用 RabbitMQ 集群和 HAProxy 軟負(fù)載

RabbitMQ 高可用集群架構(gòu)

RabbitMQ 集群架構(gòu).png

將兩個(gè) RabbitMQ 磁盤(pán)節(jié)點(diǎn)和一個(gè) RabbitMQ 內(nèi)存節(jié)點(diǎn)組成一個(gè)內(nèi)建集群,之所以要用兩個(gè)磁盤(pán)節(jié)點(diǎn)是防止,唯一的磁盤(pán)節(jié)點(diǎn)掛掉后,不能重建隊(duì)列,交換器。用 HAProxy 作為 RabbitMQ 集群的負(fù)載均衡。為了防止 HAProxy 單點(diǎn)故障,用 Keepalived 將兩個(gè) HAProxy 節(jié)點(diǎn)做成一主一備。應(yīng)用使用 VIP(虛擬IP) 訪(fǎng)問(wèn) HAProxy 服務(wù)時(shí),默認(rèn)連接主機(jī)(Master)的 HAProxy,當(dāng)主機(jī)(Master)上的 HAProxy 故障時(shí),VIP 會(huì)漂移到備機(jī)(Backup)上,就會(huì)連接備機(jī)(Backup)上的 HAProxy 服務(wù)。

準(zhǔn)備工作

服務(wù)器安裝 docker,docker-compose,準(zhǔn)備離線(xiàn)鏡像 rabbitmq.tar,haproxy.tar。
服務(wù)器節(jié)點(diǎn)間可以相互 ping 通。

RabbitMQ 集群

使用 RabbitMQ 內(nèi)建集群,持久化隊(duì)列無(wú)法在隊(duì)列節(jié)點(diǎn)崩潰時(shí),自動(dòng)連接別的節(jié)點(diǎn)創(chuàng)建隊(duì)列,非持久化隊(duì)列可以自動(dòng)連接可用節(jié)點(diǎn)創(chuàng)建隊(duì)列。我們的項(xiàng)目使用的非持久化隊(duì)列。

至少保證有兩個(gè)磁盤(pán)節(jié)點(diǎn),否則在唯一磁盤(pán)節(jié)點(diǎn)崩潰時(shí),無(wú)法在集群中創(chuàng)建隊(duì)列,交換器等元數(shù)據(jù)。

服務(wù)分布情況

192.168.1.213 服務(wù)器部署 RabbitMQ Disc Node1。
192.168.1.203 服務(wù)器部署 RabbitMQ Disc Node2。
192.168.1.212 服務(wù)器部署 RabbitMQ RAM Node3。

創(chuàng)建第一個(gè) RabbitMQ 節(jié)點(diǎn)

登錄服務(wù)器,創(chuàng)建目錄 /app/mcst/rabbitmq。

將鏡像 tar 包 rabbitmq.tar,服務(wù)編排文件 mcst-rabbitmq-node1.yaml 通過(guò) sftp 上傳到剛創(chuàng)建的目錄下。

導(dǎo)入鏡像

$ docker load -i rabbitmq.tar
$ docker images # 查看是否導(dǎo)入成功

查看服務(wù)編排文件 mcst-rabbitmq-node1.yaml

version: '3'
services:
  rabbitmq:
    container_name: mcst-rabbitmq
    image: rabbitmq:3-management
    restart: always
    ports:
      - 4369:4369
      - 5671:5671
      - 5672:5672
      - 15672:15672
      - 25672:25672
    environment:
      - TZ=Asia/Shanghai
      - RABBITMQ_ERLANG_COOKIE=iweru238roseire
      - RABBITMQ_DEFAULT_USER=mcst_admin
      - RABBITMQ_DEFAULT_PASS=mcst_admin_123
      - RABBITMQ_DEFAULT_VHOST=mcst_vhost
    hostname: rabbitmq1
    extra_hosts:
      - rabbitmq1:192.168.1.213
      - rabbitmq2:192.168.1.203
      - rabbitmq3:192.168.1.212
    volumes:
      - ./data:/var/lib/rabbitmq

部署命令

$ docker-compose -f mcst-rabbitmq-node1.yaml up -d

注意:三個(gè)節(jié)點(diǎn) RABBITMQ_ERLANG_COOKIE 保持一致。一定要有 extra_hosts 配置,否則在搭建集群的過(guò)程中會(huì)連接不到其他 rabbitmq 節(jié)點(diǎn)服務(wù)。此節(jié)點(diǎn)作為集群根節(jié)點(diǎn)。

部署第二個(gè) RabbitMQ 節(jié)點(diǎn)

方法同上,上傳 rabbitmq.sh 腳本到 volumes 配置的 ./rabbitmq.sh 路徑。查看 mcst-rabbitmq-node2.yaml

version: '3'
services:
  rabbitmq:
    container_name: mcst-rabbitmq
    image: rabbitmq:3-management
    restart: always
    ports:
      - 4369:4369
      - 5671:5671
      - 5672:5672
      - 15672:15672
      - 25672:25672
    environment:
      - TZ=Asia/Shanghai
      - RABBITMQ_ERLANG_COOKIE=iweru238roseire
      - RABBITMQ_DEFAULT_USER=mcst_admin
      - RABBITMQ_DEFAULT_PASS=mcst_admin_123
      - RABBITMQ_DEFAULT_VHOST=mcst_vhost
    hostname: rabbitmq2
    extra_hosts:
      - rabbitmq1:192.168.1.213
      - rabbitmq2:192.168.1.203
      - rabbitmq3:192.168.1.212
    volumes:
      - ./rabbitmq.sh:/home/rabbitmq.sh
      - ./data:/var/lib/rabbitmq

部署命令

$ docker-compose -f mcst-rabbitmq-node2.yaml up -d

節(jié)點(diǎn)啟動(dòng)完成后,通過(guò)命令進(jìn)入 rabbitmq2 節(jié)點(diǎn)的容器中,執(zhí)行 /home/rabbitmq.sh 腳本。如果報(bào)權(quán)限錯(cuò)誤,則在容器內(nèi)執(zhí)行 chmod +x /home/rabbitmq.sh 賦權(quán),然后 bash /home/rabbitmq.sh 執(zhí)行腳本添加到集群中。

進(jìn)入容器的命令:

$ docker exec -it mcst-rabbitmq /bin/bash

腳本內(nèi)容如下(磁盤(pán)節(jié)點(diǎn)):

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbitmq1
rabbitmqctl start_app

部署第三個(gè) RabbitMQ 節(jié)點(diǎn)

方法同上,查看 mcst-rabbitmq-node3.yaml

version: '3'
services:
  rabbitmq:
    container_name: mcst-rabbitmq
    image: rabbitmq:3-management
    restart: always
    ports:
      - 4369:4369
      - 5671:5671
      - 5672:5672
      - 15672:15672
      - 25672:25672
    environment:
      - TZ=Asia/Shanghai
      - RABBITMQ_ERLANG_COOKIE=iweru238roseire
      - RABBITMQ_DEFAULT_USER=mcst_admin
      - RABBITMQ_DEFAULT_PASS=mcst_admin_123
      - RABBITMQ_DEFAULT_VHOST=mcst_vhost
    hostname: rabbitmq3
    extra_hosts:
      - rabbitmq1:192.168.1.213
      - rabbitmq2:192.168.1.203
      - rabbitmq3:192.168.1.212
    volumes:
      - ./rabbitmq-ram.sh:/home/rabbitmq-ram.sh
      - ./data:/var/lib/rabbitmq

部署命令

$ docker-compose -f mcst-rabbitmq-node3.yaml up -d

在啟動(dòng) rabbitmq3 節(jié)點(diǎn),啟動(dòng)后,進(jìn)入容器內(nèi)部,執(zhí)行 bash /home/rabbitmq-ram.sh 腳本添加內(nèi)存節(jié)點(diǎn)到集群中。

腳本內(nèi)容:

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbitmq1
rabbitmqctl start_app

在容器內(nèi)部使用命令查看集群狀態(tài):rabbitmqctl cluster_status。

Cluster status of node rabbit@rabbitmq1 ...
[{nodes,[{disc,[rabbit@rabbitmq1,rabbit@rabbitmq2]},{ram,[rabbit@rabbitmq3]}]},
 {running_nodes,[rabbit@rabbitmq2,rabbit@rabbitmq3,rabbit@rabbitmq1]},
 {cluster_name,<<"rabbit@rabbitmq2">>},
 {partitions,[]},
 {alarms,[{rabbit@rabbitmq2,[]},{rabbit@rabbitmq3,[]},{rabbit@rabbitmq1,[]}]}]

也可以通過(guò) http://192.168.1.213:15672 進(jìn)入管理端查看集群狀態(tài)。

rabbitmq集群.jpg

HAProxy 負(fù)載均衡

創(chuàng)建目錄 /app/mcst/haproxy,將鏡像 tar 包,haproxy 配置文件,docker 服務(wù)編排文件上傳到該目錄。

導(dǎo)入鏡像方法同上。

查看服務(wù)編排文件內(nèi)容:

version: '3'
services:
  haproxy:
    container_name: mcst-haproxy
    image: haproxy:2.1
    restart: always
    ports:
      - 8100:8100
      - 15670:5670
    environment:
      - TZ=Asia/Shanghai
    extra_hosts:
      - rabbitmq1:192.168.1.213
      - rabbitmq2:192.168.1.203
      - rabbitmq3:192.168.1.212
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro

重點(diǎn)是設(shè)置 extra_hosts(rabbitmq 集群節(jié)點(diǎn) ip) 和 volumes(使用自定義的配置文件)。

haproxy 配置文件內(nèi)容:

global
    log 127.0.0.1 local0 info
    maxconn 4096

defaults
    log     global
    mode    tcp
    option  tcplog
    retries 3
    option  redispatch
    maxconn 2000
    timeout connect 5s
    timeout client 120s
    timeout server 120s

# ssl for rabbitmq
# frontend ssl_rabbitmq
    # bind *:5673 ssl crt /root/rmqha_proxy/rmqha.pem
    # mode tcp
    # default_backend rabbitmq

# web 管理界面
listen stats
    bind *:8100
    mode http
    stats enable
    stats realm Haproxy\ Statistics
    stats uri /
    stats auth admin:admin123
# 配置負(fù)載均衡
listen rabbitmq
    bind *:5670
    mode tcp
    balance roundrobin
    server  rabbitmq1 rabbitmq1:5672  check inter 5s rise 2 fall 3
    server  rabbitmq2 rabbitmq2:5672  check inter 5s rise 2 fall 3
    server  rabbitmq3 rabbitmq3:5672  check inter 5s rise 2 fall 3

部署命令

$ docker-compose -f mcst-haproxy.yaml up -d

服務(wù)分布情況

192.168.1.212 服務(wù)器部署 HAProxy Master。
192.168.1.203 服務(wù)器部署 HAProxy Backup。

分別在以上兩個(gè)節(jié)點(diǎn)起好 HAProxy 服務(wù)。

登錄 HAProxy 的管理端查看集群狀態(tài):http://192.168.1.212:8100/。

haproxy.jpg

使用 Keepalived 給 HAProxy 做主備

準(zhǔn)備工作

申請(qǐng)一個(gè)和服務(wù)節(jié)點(diǎn)同一局域網(wǎng)的 ip 地址,該 ip 不能被占用,作為 VIP(虛擬ip)。

安裝 Keepalived

到 Keepalived 官網(wǎng)下載最新版本包,本次安裝使用的是 2.0.20 版本。
下載好后的文件是:keepalived-2.0.20.tar.gz。

上傳到服務(wù)器,對(duì) tar 包解壓縮。

$ tar -xf keepalived-2.0.20.tar.gz

檢查依賴(lài)

$ cd keepalived-2.0.20
$ ./configure

Keepalived 的安裝需要以下依賴(lài) gcc,openssl-devel。

安裝命令

$ yum install -y gcc
$ yum install -y openssl-devel

因?yàn)槭莾?nèi)網(wǎng)服務(wù)器不能使用外網(wǎng)的 yum 源,所以需要更改用本地 yum 源。

搭建本地 yum 源的參考文章

將 linux 的安裝光盤(pán)鏡像上傳到 /mnt/iso 目錄下,并 mount 到 /mnt/cdrom 目錄下,作為 yum 的一個(gè)安裝源。

$ mkdir /mnt/iso
$ mkdir /mnt/cdrom 
$ mv /ftp/rhel-server-7.3-x86_64-dvd.iso /mnt/iso

掛載光盤(pán)鏡像

$ mount -ro loop /mnt/iso/rhel-server-7.3-x86_64-dvd.iso /mnt/cdrom 
$ mv /ftp/myself.repo /etc/yum.repos.d
$ yum clean all 
$ yum makecache 
$ yum update

附:myself.repo文件內(nèi)容:

[base]
name= Red Hat  Enterprise Linux $releasever  -  $basearch  -  Source
baseurl=file:///mnt/cdrom
enabled=1
gpgcheck=1
gpgkey=file:///mnt/cdrom/RPM-GPG-KEY-redhat-release

更改完成后,以后每次需要 linux 安裝盤(pán)安裝軟件包時(shí),只需要執(zhí)行 mount 命令,將光盤(pán) ISO 文件加載即可。

$ mount -ro loop /mnt/iso/rhel-server-7.3-x86_64-dvd.iso /mnt/cdrom 

這時(shí)使用 yum 安裝 gcc,openssl-devel就沒(méi)問(wèn)題了。

如果使用本地 yum 源的條件也不具備,那么可以使用 yum 的 downloadonly 插件。

要在能連接外網(wǎng)和系統(tǒng)版本一致的機(jī)器上將需要的依賴(lài)下載下來(lái),到目標(biāo)內(nèi)網(wǎng)機(jī)器上本地安裝。

downloadonly 使用方法的參考文章

還是推薦使用本地 yum 源的方式。

安裝完 gcc,openssl-devel 后,再次執(zhí)行 ./configure 會(huì)報(bào)一個(gè)警告。

“this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.”

安裝如下依賴(lài)解決

$ yum install -y libnl libnl-devel

安裝完成后再次 ./configure 就沒(méi)問(wèn)題了。

然后執(zhí)行 make 編譯

最后執(zhí)行 make install 安裝

安裝完成后執(zhí)行 keepalived --version,輸出版本號(hào)即為安裝成功。

創(chuàng)建 Keepalived 配置文件

創(chuàng)建配置文件 /etc/keepalived/keepalived.conf

Master 節(jié)點(diǎn)配置:

vrrp_script chk_haproxy {
    script "killall -0 haproxy"  # verify haproxy's pid existance
    interval 5                   # check every 2 seconds
    weight -2                    # if check failed, priority will minus 2
}
vrrp_instance VI_1 {
    # 主機(jī): MASTER
    # 備機(jī): BACKUP
    state MASTER
    # 實(shí)例綁定的網(wǎng)卡, 用ip a命令查看網(wǎng)卡編號(hào)
    interface ens192
    # 虛擬路由標(biāo)識(shí),這個(gè)標(biāo)識(shí)是一個(gè)數(shù)字(1-255),在一個(gè)VRRP實(shí)例中主備服務(wù)器ID必須一樣
    virtual_router_id 51
    # 優(yōu)先級(jí),數(shù)字越大優(yōu)先級(jí)越高,在一個(gè)實(shí)例中主服務(wù)器優(yōu)先級(jí)要高于備服務(wù)器
    priority 101
    # 虛擬IP地址,可以有多個(gè),每行一個(gè)
    virtual_ipaddress {
        192.168.1.110
    }
    track_script {               # Scripts state we monitor
        chk_haproxy              
    }
}

ens192 是網(wǎng)卡名,ifconfig 命令查看服務(wù)器網(wǎng)卡,找到和本機(jī)服務(wù) ip 對(duì)應(yīng)的網(wǎng)卡,virtual_router_id 的值要和 backup 節(jié)點(diǎn)上的配置保持一致。killall -0 haproxy 命令的意思是,如果 haproxy 服務(wù)存在執(zhí)行該命令,什么都不會(huì)發(fā)生,如果服務(wù)不存在,執(zhí)行該命令會(huì)報(bào)找不到進(jìn)程 haproxy: no process found。

# 網(wǎng)卡信息
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.203  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::250:56ff:fe94:bceb  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:94:bc:eb  txqueuelen 1000  (Ethernet)
        RX packets 88711011  bytes 12324982140 (11.4 GiB)
        RX errors 0  dropped 272  overruns 0  frame 0
        TX packets 88438149  bytes 10760989492 (10.0 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# haproxy 服務(wù)不存在
[root@localhost ~]# killall -0 haproxy
haproxy: no process found

master 節(jié)點(diǎn)的 priority 在減去 weight 后要比 backup 節(jié)點(diǎn)的 priority 低才行,否則主備切換不成功。

Backup節(jié)點(diǎn)配置:

vrrp_script chk_haproxy {
    script "killall -0 haproxy"  # verify haproxy's pid existance
    interval 5                   # check every 2 seconds
    weight -2                    # if check failed, priority will minus 2
}
vrrp_instance VI_1 {
    # 主機(jī): MASTER
    # 備機(jī): BACKUP
    state BACKUP
    # 實(shí)例綁定的網(wǎng)卡, 用ip a命令查看網(wǎng)卡編號(hào)
    interface ens192
    # 虛擬路由標(biāo)識(shí),這個(gè)標(biāo)識(shí)是一個(gè)數(shù)字(1-255),在一個(gè)VRRP實(shí)例中主備服務(wù)器ID必須一樣
    virtual_router_id 51
    # 優(yōu)先級(jí),數(shù)字越大優(yōu)先級(jí)越高,在一個(gè)實(shí)例中主服務(wù)器優(yōu)先級(jí)要高于備服務(wù)器
    priority 100
    # 虛擬IP地址,可以有多個(gè),每行一個(gè)
    virtual_ipaddress {
        192.168.1.110
    }
    track_script {               # Scripts state we monitor
        chk_haproxy              
    }
}

創(chuàng)建完配置,啟動(dòng) keepalived。

$ systemctl restart keepalived

測(cè)試 Keepalived

在 Master,Backup 節(jié)點(diǎn)上,使用 ip addr 命令看下 vip 在哪臺(tái)機(jī)器的 ens192 網(wǎng)卡上。

2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    link/ether 00:50:56:94:c1:79 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.212/24 brd 192.168.1.255 scope global ens192
       valid_lft forever preferred_lft forever
    inet 192.168.1.110/32 scope global ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fe94:c179/64 scope link 
       valid_lft forever preferred_lft forever

默認(rèn)在 master 主機(jī)上,停掉 master 主機(jī)的 haproxy 服務(wù),然后在用 ip addr 查看虛擬 ip 在哪個(gè)機(jī)器上,如果漂移到備份主機(jī)上則代表熱備生效。

在開(kāi)啟 master 主機(jī)的 haproxy 服務(wù),ip addr 查看虛擬ip應(yīng)該重新漂移回 master 主機(jī)上。

測(cè)試服務(wù),使用虛擬 ip 加服務(wù)端口號(hào)訪(fǎng)問(wèn) HAProxy 服務(wù)。

至此,高可用的 rabbitmq 集群 和 haproxy 軟負(fù)載就搭建完成。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容