Deploy HA-RabbitMQ
CentOS7 部署高可用 RabbitMQ
一. 安装说明
一般单节点负载过高会导致服务响应过慢,使用集群方式则能够避免这种情况,通过 HAProxy 实现负载均衡,再使用 Keepalived 服务实现虚拟 VIP-IP 异常漂移,任一节点服务宕机均不会影响服务的正常运行
RabbitMQ 集群可使得 RabbitMQ 节点宕机时,消费者和生产者都可以正常继续运行,并且可以承载更多的业务量,增加系统吞吐量;
客户端通过虚拟 IP 进行访问 HAProxy,再通过 Keepalived 将其发放到 Master 节点上的 HAProxy,若 Master 节点上的 HAProxy 宕机,则会发放到 Slave 节点上,之后访问到 RabbitMQ 集群

| IP | 主机名 | 服务 | 
| 188.188.4.210 | ssd-dev01 | RabbitMQ | 
| 188.188.4.211 | ssd-dev02 | RabbitMQ+HAProxy+Keepalived | 
| 188.188.4.212 | ssd-dev03 | RabbitMQ+HAProxy+Keepalived | 
|  | # 所有节点提前配置hostname
$ hostnamectl set-hostname ssd-dev01 && bash
$ hostnamectl set-hostname ssd-dev02 && bash
$ hostnamectl set-hostname ssd-dev03 && bash
$ cat >> /etc/hosts << EOF
188.188.4.210 ssd-dev01
188.188.4.211 ssd-dev02
188.188.4.212 ssd-dev03
EOF
 | 
安装方法很多,可自行选择,如使用 yum -y install 命令进行安装,本文选择源码安装的原因主要是方便管理,建议实际生产中尽量使用源码安装,方便后期运维管理
- Linux 版本:CentOS Linux release 7.9.2009 (Core)
- erlang 版本:Erlang-23.3.4.11
- RabbitMQ 版本:RabbitMQ_Server-3.8.29
- HAProxy 版本:Haproxy-2.5.5
- Keepalived 版本:Keepalived-2.2.7
二. 安装 Erlang
安装前建议参考 Erlang Github 官方说明,Readme 上有说明版本的兼容性问题
|  | # 安装依赖
$ yum -y install socat
# 在此选用了rpm方式安装,因为二进制源码安装会报错,需要修改配置文件的环境变量
$ wget https://github.com/rabbitmq/erlang-rpm/releases/download/v23.3.4.11/erlang-23.3.4.11-1.el7.x86_64.rpm
$ rpm -i erlang-23.3.4.11-1.el7.x86_64.rpm
warning: erlang-23.3.4.11-1.el7.x86_64.rpm: Header V4 RSA/SHA256 Signature, key ID cc4bbe5b: NOKEY
$ erl -version
Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 11.2.2.10
 | 
三. 安装 RabbitMQ
1)下载程序并配置环境变量
|  | $ wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.29/rabbitmq-server-generic-unix-3.8.29.tar.xz
$ tar -xvf rabbitmq-server-generic-unix-3.8.29.tar.xz -C /opt/
$ cd /opt && mv rabbitmq_server-3.8.29 rabbitmq
$ echo 'export PATH=/opt/rabbitmq/sbin:$PATH' >> /etc/profile
$ source /etc/profile
 | 
2)创建用户并修改权限
|  | $ useradd rabbitmq
$ mkdir -p /opt/rabbitmq/var/lib/rabbitmq /opt/rabbitmq/var/log/rabbitmq
$ chown rabbitmq.rabbitmq -R /opt/rabbitmq
 | 
3)创建配置文件
|  | # 添加浏览器管理插件,默认安装是没有管理页面
$ cat >> /opt/rabbitmq/etc/rabbitmq/enabled_plugins <<EOF
[rabbitmq_management].
EOF
 | 
|  | # 注意$hostname自行修改节点实际hostname
$ cat >> /opt/rabbitmq/etc/rabbitmq/rabbitmq-env.conf <<EOF
RABBITMQ_NODENAME=rabbit@$hostname
RABBITMQ_NODE_IP_ADDRESS=0.0.0.0
RABBITMQ_NODE_PORT=5672
RABBITMQ_LOG_BASE=/opt/rabbitmq/var/log/rabbitmq
RABBITMQ_MNESIA_BASE=/opt/rabbitmq/var/lib/rabbitmq/mnesia
EOF
 | 
|  | $ cat >> /opt/rabbitmq/etc/rabbitmq/rabbitmq.conf <<EOF
listeners.tcp.default = 5672
num_acceptors.tcp = 10
management.tcp.port = 15672
management.tcp.ip   = 0.0.0.0
management.http_log_dir = /opt/rabbitmq/var/log/rabbitmq/management_access
vm_memory_high_watermark.absolute = 512MiB
vm_memory_high_watermark_paging_ratio = 0.3
loopback_users.guest = true
EOF
 | 
4)配置开机自启动服务
|  | $ cat >> /etc/systemd/system/rabbitmq-server.service <<EOF
[Unit]
Description=RabbitMQ broker
After=syslog.target network.target
[Service]
Type=notify
User=rabbitmq
Group=rabbitmq
UMask=0027
NotifyAccess=all
TimeoutStartSec=3600
LimitNOFILE=32768
Restart=on-failure
RestartSec=10
WorkingDirectory=/opt/rabbitmq/var/lib/rabbitmq
ExecStart=/opt/rabbitmq/sbin/rabbitmq-server
ExecStop=/opt/rabbitmq/sbin/rabbitmqctl shutdown
SuccessExitStatus=69
[Install]
WantedBy=multi-user.target
EOF
 | 
5)设置 Cookie 并启动
|  | $ echo "rabbitmq-cluster-cookie" >> ~/.erlang.cookie
$ echo "rabbitmq-cluster-cookie" >> /home/rabbitmq/.erlang.cookie
$ chown rabbitmq.rabbitmq /home/rabbitmq/.erlang.cookie
$ chmod 600 ~/.erlang.cookie /home/rabbitmq/.erlang.cookie
$ systemctl daemon-reload && systemctl enable --now rabbitmq-server
$ systemctl status rabbitmq-server
 | 
6)添加 RabbitMQ 账密,并分配权限
|  | # 检查用户列表
$ rabbitmqctl list_users
Listing users ...
user    tags
guest   [administrator]
rabbitmq_user   []
# RabbitMQ 有默认用户密码,guest/guest该用户密码只能在本地登陆,若在浏览器中登陆,须创建新用户密码
$ rabbitmqctl add_user rabbitmq_user rabbitmq_pwd
Adding user "rabbitmq_user" ...
Done. Don't forget to grant the user permissions to some virtual hosts! See 'rabbitmqctl help set_permissions' to learn more.
# 为rabbitmq_user用户添加管理员角色
$ rabbitmqctl set_user_tags rabbitmq_user administrator 
Setting tags for user "rabbitmq_user" to [administrator] ...
# 设置rabbitmq_user用户权限,允许访问vhost及read/write
$ rabbitmqctl set_permissions -p / rabbitmq_user ".*" ".*" ".*"
Setting permissions for user "rabbitmq_user" in vhost "/" ...
# 检查权限列表
$ rabbitmqctl list_permissions -p /
Listing permissions for vhost "/" ...
user    configure   write   read
rabbitmq_user   .*  .*  .*
guest   .*  .*  .*
 | 
四. 配置集群
1)RabbitMQ 集群添加节点,分别在 ssd-dev02、ssd-dev03 上执行如下命令,将其加入集群中
|  | # ssd-dev02操作
$ rabbitmqctl stop_app
$ rabbitmqctl join_cluster --ram rabbit@ssd-dev01
$ rabbitmqctl start_app
# ssd-dev03操作
$ rabbitmqctl stop_app
$ rabbitmqctl join_cluster --ram rabbit@ssd-dev01
$ rabbitmqctl start_app
 | 
2)验证集群是否配置成功
|  | $ rabbitmqctl cluster_status
Cluster status of node rabbit@ssd-dev01 ...
Basics
Cluster name: rabbit@ssd-dev01
Disk Nodes
rabbit@ssd-dev01
RAM Nodes
rabbit@ssd-dev02
rabbit@ssd-dev03
Running Nodes
rabbit@ssd-dev01
rabbit@ssd-dev02
rabbit@ssd-dev03
Versions
rabbit@ssd-dev01: RabbitMQ 3.8.2 on Erlang 23.3.4.11
rabbit@ssd-dev02: RabbitMQ 3.8.2 on Erlang 23.3.4.11
rabbit@ssd-dev03: RabbitMQ 3.8.2 on Erlang 23.3.4.11
...(略)
 | 
或使用任一节点在浏览器上打开 IP:15672 管理页面,显示绿色表示成功
3)配置镜像队列,配置可参考文档,policy 策略的意思就是要设置 Exchanges 或者 queue 的数据需要如何复制、同步,可通过命令方式和管理页面方式实现。
|  | # policy配置格式,命令行配置镜像队列,在任一节点上执行如下命令,示例如下
$ rabbitmqctl set_policy [-p ] [--priority ] [--apply-to ] 
$ rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
# 同步virtual host为 "/"下名称前缀为 "mirroring"的交换机和队列,并且自动保存到两个节点上
$ rabbitmqctl set_policy -p / --priority 1 --apply-to all myPolicy "^mirroring" '{"ha-mode":"exactly","ha-params":3,"ha-sync-mode":"automatic"}'
 | 
五. 安装 Haproxy
1)解压编译安装
|  | $ yum -y install glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel zlib-devel
$ wget https://www.haproxy.org/download/2.5/src/haproxy-2.5.5.tar.gz
$ tar -zxvf haproxy-2.5.5.tar.gz && cd haproxy-2.5.5
$ make ARCH=x86_64 \
  TARGET=linux-glibc \
  USE_PCRE=1 \
  USE_OPENSSL=1 \
  USE_ZLIB=1 \
  USE_SYSTEMD=1 \
  USE_CPU_AFFINITY=1 \
  PREFIX=/opt/haproxy
$ make install PREFIX=/opt/haproxy  
 | 
参数说明:
- ARCH=x86_64 表示使用 ARCH 指定框架,可选项
- TARGET=linux-glibc 通用 linux 内核
- USE_PCRE=1 PCRE 支持正则表达式,用于用户请求的 uri
- USE_OPENSSL=1 https,证书
- USE_ZLIB=1 开启压缩
- USE_SYSTEMD=1 使用 systemd 启动 haproxy 主进程
- PREFIX=/opt/haproxy 指定安装路径
2)设置环境变量
|  | $ echo 'export PATH=/opt/haproxy/sbin:$PATH' >> /etc/profile
$ source /etc/profile
$ haproxy -v
HAProxy version 2.5.5-384c5c5 2022/03/14 - https://haproxy.org/
Status: stable branch - will stop receiving fixes around Q1 2023.
Known bugs: http://www.haproxy.org/bugs/bugs-2.5.5.html
Running on: Linux 5.4.188-1.el7.elrepo.x86_64 #1 SMP Mon Mar 28 09:10:07 EDT 2022 x86_64
 | 
3)创建配置文件,节点2 & 节点3 配置一样
|  | $ mkdir -p /etc/haproxy
$ vim /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
log 127.0.0.1 local0 info
pidfile /opt/haproxy/haproxy.pid          # haproxy的pid存放路径,启动进程的用户必须有权限访问此文件
maxconn 4000                              # 最大连接数,默认4000
daemon                                    # 创建1个进程进入deamon模式运行。此参数要求将运行模式设置为daemon
#---------------------------------------------------------------------
# defaults settings
#---------------------------------------------------------------------
# 注意:因为要使用tcp的负载,屏蔽掉与http相关的默认配置
defaults
mode http                                 # 默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK
log global
option httplog                            # 采用http日志格式
option dontlognull                        # 启用该项,日志中将不会记录空连接。所谓空连接就是在上游的负载均衡器
option http-server-close                  # 每次请求完毕后主动关闭http通道
option forwardfor except 127.0.0.0/8      # 如果后端服务器需要获得客户端真实ip需要配置的参数,可以从Http Header中获得客户端ip
option redispatch                         # serverId对应的服务器挂掉后,强制定向到其他健康的服务器
retries 3                                 # 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                              # 最大连接数
#--------------------------------------------------------
### haproxy 监控页面地址是:http://IP:1080/hastatus
listen admin_stats
    bind *:1080                           # 监听的地址和端口,默认端口1080
    mode http                             # 模式
    option tcplog
    stats refresh 5s                      # 页面自动刷新间隔,每隔5s刷新
    stats uri /hastatus                   # 访问路径,在域名后面添加/stats可以查看haproxy监控状态,默认为/haproxy?stats
    stats realm welcome login\ Haproxy    # 提示信息,空格之前加\
    stats auth admin:123456               # 登陆用户名和密码
    stats hide-version                    # 隐藏软件版本号
    stats admin if TRUE                   # 当通过认证才可管理
#-------------------------------------------------
frontend rabbitmq
    mode tcp
    bind *:5679
    timeout client 168h
    default_backend rabbitmq_nodes
    log global
    option tcplog
backend rabbitmq_nodes
    mode tcp
    balance roundrobin
    server ssd-dev01 188.188.4.210:5672 check inter 2000 rise 2 fall 3 weight 1  #节点一
    server ssd-dev02 188.188.4.211:5672 check inter 2000 rise 2 fall 3 weight 1  #节点二
    server ssd-dev03 188.188.4.212:5672 check inter 2000 rise 2 fall 3 weight 1  #节点三
#rabbitmq 集群配置
listen rabbitmq_admin
    bind  0.0.0.0:15679
    mode http
    balance roundrobin
    server ssd-dev01 188.188.4.210:15672 check inter 2000 rise 2 fall 3 weight 1  #节点一
    server ssd-dev02 188.188.4.211:15672 check inter 2000 rise 2 fall 3 weight 1  #节点二
    server ssd-dev03 188.188.4.212:15672 check inter 2000 rise 2 fall 3 weight 1  #节点三
 | 
开启日志记录:安装 Haproxy 之后,默认是没有开启日志记录的,需要根据 rsyslog 通过 udp 的方式获取 Haproxy 日志信息
|  | $ vim /etc/rsyslog.conf
    # 打开以下两行注解,开启 514 USP监听
    $ModLoad imudp
    $UDPServerRun 514
    # 添加日志目录 (local0与haproxy.cfg中global log保持一致)
    local2.*   /var/log/haproxy/haproxy.log
$ vim /etc/sysconfig/rsyslog
    # 修改如下内容(若没有则添加)
    SYSLOGD_OPTIONS="-r -m 0 -c 2"
# 重启生效
$ systemctl restart rsyslog && systemctl status rsyslog
 | 
3)启动并查看状态,配置开机自启
|  | $ haproxy -f /etc/haproxy/haproxy.cfg
Configuration file is valid
$ lsof -i:1080
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
haproxy 3296 root    4u  IPv4  26318      0t0  TCP *:socks (LISTEN)
 | 
|  | $ cat >> /usr/lib/systemd/system/haproxy.service << EOF
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target
[Service]
ExecStartPre=/opt/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c
ExecStart=/opt/haproxy/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /opt/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 \$MAINPID
[Install]
WantedBy=multi-user.target
EOF
$ systemctl enable --now haproxy && systemctl status haproxy
 | 
4)使用浏览器访问 IP:1080/hastatus,输入账密即可访问 Haproxy 监控界面

六. 安装 Keepalived
1)安装依赖并下载程序解压
|  | $ yum install -y gcc openssl-devel popt-devel ipvsadm libnl3-devel net-snmp-devel libnl libnl-devel libnfnetlink-devel
$ wget https://www.keepalived.org/software/keepalived-2.2.7.tar.gz
$ tar -xf keepalived-2.2.7.tar.gz && cd keepalived-2.2.7
 | 
2)编译安装
|  | $ ./configure --prefix=/opt/keepalived
$ make && make install
 | 
3)创建配置文件
|  | $ mkdir -p /etc/keepalived
# keepalived默认读取的配置文件
$ cp /opt/keepalived/etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf
# 配置启动服务
$ cp /usr/local/src/keepalived-2.2.7/keepalived/etc/init.d/keepalived /etc/init.d
$ cp /opt/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
$ cp /opt/keepalived/sbin/keepalived /usr/sbin/
 | 
4)节点2 & 节点3 修改配置文件
|  | # ssd-dev02
$ vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
   script_user root
   enable_script_security
   router_id node1
   vrrp_skip_check_adv_addr
#   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_instance VI_1 {
    #keepalived角色,MASTER表示主节点 BACKUP从节点
    state MASTER
    #指定检测的网卡
    interface ens192
    #虚拟路由的id,主备节点设置相同
    virtual_router_id 240
    #优先级,主节点的优先级需要设置的比从节点高
    priority 100
    #设置主备之间的检查时间,单位s
    advert_int 1
    #定义验证类型和密码
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 另一个节点的ip
    unicast_peer {
        188.188.4.212
    }
    #虚拟ip
    virtual_ipaddress {
        188.188.4.200
    }
}
virtual_server 188.188.4.200 1080 {
    virtual_server 
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP
    real_server 188.188.4.211 1080 {
        weight 1
    # 监控脚本
        notify_down /etc/keepalived/check.sh
        TCP_CHECK {
          connect_timeout 10
          retry 3
          connect_port 1080
        }
    }
}
 | 
|  | # ssd-dev03
$ vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
   script_user root
   enable_script_security
   router_id node2
   vrrp_skip_check_adv_addr
#   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_instance VI_1 {
    #keepalived角色,MASTER表示主节点 BACKUP从节点
    state BACKUP
    #指定检测的网卡
    interface ens192
    #虚拟路由的id,主备节点设置相同
    virtual_router_id 240
    #优先级,主节点的优先级需要设置的比从节点高
    priority 90
    #设置主备之间的检查时间,单位s
    advert_int 1
    #定义验证类型和密码
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 另一个节点的ip
    unicast_peer {
        188.188.4.211
    }
    #虚拟ip
    virtual_ipaddress {
        188.188.4.200
    }
}
virtual_server 188.188.4.200 1080 {
    virtual_server 
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP
    real_server 188.188.4.212 1080 {
        weight 1
    # 监控脚本
        notify_down /etc/keepalived/check.sh
        TCP_CHECK {
          connect_timeout 10
          retry 3
          connect_port 1080
        }
    }
}
 | 
5)创建 check 脚本
|  | # 脚本内容 监听haproxy端口1080
$ cat /etc/keepalived/check.sh
#! /bin/bash
counter=$(ss -tanlp | grep "LISTEN" | grep "1080"|wc -l)
if [ "${counter}" -eq 0 ]
then
   pkill keepalived
fi
$ chmod +x /etc/keepalived/check.sh
 | 
6)启动并设置开机自启
|  | $ /etc/init.d/keepalived start
$ systemctl enable keepalived && systemctl status keepalived
 |