RabbitMQ高可用集群搭建手册(镜像模式)
本文大部分摘抄自这篇博客RabbitMQ 高可用集群搭建,本人根据RabbitMQ官方文档修正了部分内容、增加了数据目录更改,调整了整个文档目录。
一、前言
问:如何保证RabbitMQ消息不丢失、不重复(消息幂等)?
答:生产者:
超时、重传(ACK)、持久化
;消费者:消息内部ID
。也可采用镜像模式实现高可用集群
,尽可能的降低数据丢失风险。
二、部署架构
- 基础环境
操作系统 CentOS 7.9
内存 16G
CPU 4核
主机名 | IP | VIP | Port | 部署服务 |
---|---|---|---|---|
rabbit-node1 | 192.168.63.17 | 192.168.63.200 | 5672/tcp 15672/tcp 25672/tcp 4369/tcp 8100/tcp 5671/tcp 15671/tcp | RabbitMQ + HAProxy(主) + KeepAlived |
rabbit-node2 | 192.168.63.19 | 192.168.63.200 | 5672/tcp 15672/tcp 25672/tcp 4369/tcp 8100/tcp 5671/tcp 15671/tcp | RabbitMQ + HAProxy(备) + KeepAlived |
rabbit-node3 | 192.168.63.20 | 5672/tcp 15672/tcp 25672/tcp 4369/tcp | RabbitMQ |
三、基础配置
1.hosts
cat >> /etc/hosts <<EOF
192.168.63.17 rabbit-node1
192.168.63.19 rabbit-node2
192.168.63.20 rabbit-node3
EOF
2.设置hostname
注意:一旦RabbitMQ启动完成,不允许随意调整主机名,避免RabbitMQ服务异常。
- rabbit-node1
hostname rabbit-node1 && hostnamectl set-hostname rabbit-node1
- rabbit-node2
hostname rabbit-node2 && hostnamectl set-hostname rabbit-node2
- rabbit-node3
hostname rabbit-node3 && hostnamectl set-hostname rabbit-node3
3.防火墙配置
RabbitMQ防火墙配置,其中4369为epmd进程使用的端口。用于RabbitMQ节点和CLI工具的端点发现服务。
firewall-cmd --zone=public --add-port=5672/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=4369/tcp --permanent
firewall-cmd --reload
haproxy防火墙配置
firewall-cmd --zone=public --add-port=5671/tcp --permanent
firewall-cmd --zone=public --add-port=15671/tcp --permanent
firewall-cmd --zone=public --add-port=8100/tcp --permanent
firewall-cmd --reload
4.selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
sed -i 's/SELINUX=permissive/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
getenforce
四、RabbitMQ安装和配置
单机版安装教程,请参考我的另一篇博客 CentOS 7 安装RabbitMQ 3.8.9
1.安装
yum安装可参考 官方安装教程-install-rpm.html
mkdir /opt/rabbitmq
cd /opt/rabbitmq
wget https://github.com/rabbitmq/erlang-rpm/releases/download/v22.3.4.12/erlang-22.3.4.12-1.el7.x86_64.rpm
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.9/rabbitmq-server-3.8.9-1.el7.noarch.rpm
yum install socat logrotate -y
rpm -ivh erlang-22.3.4.12-1.el7.x86_64.rpm rabbitmq-server-3.8.9-1.el7.noarch.rpm
- rabbit-node2和rabbit-node3可通过scp复制
cd /opt
scp -r ./rabbitmq root@rabbit-node2:/opt
scp -r ./rabbitmq root@rabbit-node3:/opt
2.启用管理插件
rabbitmq-plugins enable rabbitmq_management
rabbitmq-plugins list
3.启动和关闭
systemctl start rabbitmq-server
systemctl status rabbitmq-server
systemctl stop rabbitmq-server
4.开机启动
systemctl enable rabbitmq-server
5.防火墙配置
4369为epmd进程使用的端口。用于RabbitMQ节点和CLI工具的端点发现服务。
firewall-cmd --zone=public --add-port=5672/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=4369/tcp --permanent
firewall-cmd --reload
6.死信队列
注意:内存节点不建议开启死信队列,避免服务异常。
cd /opt/rabbitmq
wget https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/3.8.9/rabbitmq_delayed_message_exchange-3.8.9-0199d11c.ez
whereis rabbitmq
cd /usr/lib/rabbitmq/lib/rabbitmq_server-3.8.9/plugins
cp /opt/rabbitmq/rabbitmq_delayed_message_exchange-3.8.9-0199d11c.ez ./
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
rabbitmq-plugins list
7.新增用户
rabbitmqctl list_users
rabbitmqctl add_user admin 123456
rabbitmqctl set_user_tags admin administrator
rabbitmqctl set_permissions -p / admin "." "." ".*"
rabbitmqctl list_users
8.访问
注意:若无法访问,提示“ReferenceError: disable_stats is not defined ReferenceError “rabbitmq”。
请清理浏览器缓存!!!
9.cookie复制
- rabbit-node1
启动
rabbit-node1
,停止rabbit-node2
和rabbit-node3
上RabbitMQ服务,复制rabbit-node1
上的cookie到另外两个节点;然后启动rabbit-node2
和rabbit-node3
上RabbitMQ服务。
ls -al /var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie root@rabbit-node2:/var/lib/rabbitmq/
scp /var/lib/rabbitmq/.erlang.cookie root@rabbit-node3:/var/lib/rabbitmq/
- rabbit-node2和rabbit-node3
systemctl start rabbitmq-server
10.加入集群
RabbitMQ 集群的搭建需要选择其中任意一个节点为基准,将其它节点逐步加入。这里我们以 rabbit-node1 为基准节点,将 rabbit-node2 和 rabbit-node3 加入集群。在 rabbit-node2 和rabbit-node3 上执行以下命令:
- rabbit-node2和rabbit-node3
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbit-node1
rabbitmqctl start_app
join_cluster 命令有一个可选的参数 --ram ,该参数代表新加入的节点是内存节点,默认是磁盘节点。如果是内存节点,则所有的队列、交换器、绑定关系、用户、访问权限和 vhost 的元数据都将存储在内存中,如果是磁盘节点,则存储在磁盘中。内存节点可以有更高的性能,但其重启后所有配置信息都会丢失,因此RabbitMQ 要求在集群中至少有一个磁盘节点,其他节点可以是内存节点。当内存节点离开集群时,它可以将变更通知到至少一个磁盘节点;然后在其重启时,再连接到磁盘节点上获取元数据信息。除非是将 RabbitMQ 用于 RPC 这种需要超低延迟的场景,否则在大多数情况下,RabbitMQ 的性能都是够用的,可以采用默认的磁盘节点的形式。这里为了演示, rabbit-node3 我就设置为内存节点。
另外,如果节点以磁盘节点的形式加入,则需要先使用 reset 命令进行重置,然后才能加入现有群集,重置节点会删除该节点上存在的所有的历史资源和数据。采用内存节点的形式加入时可以略过 reset 这一步,因为内存上的数据本身就不是持久化的。
- rabbit-node1
将集群名称修改为
my_rabbitmq_cluster
rabbitmqctl cluster_status
rabbitmqctl set_cluster_name my_rabbitmq_cluster
rabbitmqctl cluster_status
11.配置镜像队列
- 开启镜像队列
为所有队列开启镜像配置
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
- 复制系数
在上面我们指定了 ha-mode 的值为 all ,代表消息会被同步到所有节点的相同队列中。这里我们之所以这样配置,因为我们本身只有三个节点,因此复制操作的性能开销比较小。如果你的集群有很多节点,那么此时复制的性能开销就比较大,此时需要选择合适的复制系数。通常可以遵循过半写原则,即对于一个节点数为 n 的集群,只需要同步到 n/2+1 个节点上即可。此时需要同时修改镜像策略为 exactly,并指定复制系数 ha-params,示例命令如下:
rabbitmqctl set_policy ha-two "^" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
除此之外,RabbitMQ 还支持使用正则表达式来过滤需要进行镜像操作的队列,示例如下:
rabbitmqctl set_policy ha-all "^ha\." '{"ha-mode":"all"}'
此时只会对 ha 开头的队列进行镜像。更多镜像队列的配置说明,可以参考官方文档:Highly Available (Mirrored) Queues
12.集群的关闭与重启
最后关闭最先启动原则(若不知道哪台机器最后关闭,可以尝试同时启动所有节点服务)
没有一个直接的命令可以关闭整个集群,需要逐一进行关闭。但是需要保证在重启时,最后关闭的节点最先被启动。如果第一个启动的不是最后关闭的节点,那么这个节点会等待最后关闭的那个节点启动,默认进行 10 次连接尝试,超时时间为 30 秒,如果依然没有等到,则该节点启动失败。
这带来的一个问题是,假设在一个三节点的集群当中,关闭的顺序为 rabbit-node3,rabbit-node2,rabbit-node1,如果 rabbit-node1因为故障暂时没法恢复,此时 rabbit-node2和 rabbit-node3就无法启动。想要解决这个问题,可以先将 rabbit-node1 节点进行剔除,命令如下:
systemctl stop rabbitmq-server
rabbitmqctl forget_cluster_node --offline rabbit@rabbit-node1
此时需要加上
-offline
参数,它允许节点在自身没有启动的情况下将其他节点剔除。
实在不行,再使用强制启动命令
rabbitmqctl force_boot
,此种方式极有可能会丢失数据。
rabbitmqctl force_boot
systemctl stop rabbitmq-server
systemctl start rabbitmq-server
13.退出集群
- 重置当前节点
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
- 重新加入集群
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbit-node1
rabbitmqctl start_app
rabbitmqctl cluster_status
- 剔除其它节点
rabbitmqctl forget_cluster_node rabbit@rabbit-node3
14.变更节点类型
我们可以将节点的类型从RAM更改为Disk,反之亦然。假设我们想要反转rabbit@rabbit-node2和rabbit@rabbit-node1的类型,将前者从RAM节点转换为磁盘节点,而后者从磁盘节点转换为RAM节点。为此,我们可以使用change_cluster_node_type命令。必须首先停止节点。
注意:内存节点不建议开启死信队列,避免服务异常。
rabbitmqctl stop_app
rabbitmqctl change_cluster_node_type disc
rabbitmqctl start_app
15.清除节点配置(慎用)
systemctl stop rabbitmq-server
ps aux|grep rabbitmq
rm -rf /var/lib/rabbitmq/mnesia
20.RabbitMQ环境变量及配置文件
RabbitMQ配置文件分为
rabbitmq.conf
、advanced.config
、rabbitmq-env.conf
三大部分,更多说明详见 官方配置教程-configure.html
Configuration | Location(CentOS RPM) | Format Used | 示例配置文件 | Purpose |
---|---|---|---|---|
rabbitmq.conf | /etc/rabbitmq/rabbitmq.conf | New style format (sysctl or ini-like) | rabbitmq.conf.example | 主配置文件,配置风格友好,例如:key=value;另外,为了兼容RabbitMQ 3.7.0之前版本,仍保留类同advanced.config 风格的配置,但你要在环境变量中指定一个配置文件路径(必须以.config 结尾),例如RABBITMQ_CONFIG_FILE=/etc/rabbitmq/rabbitmq.config |
advanced.config | /etc/rabbitmq/advanced.config | Classic (Erlang terms) | advanced.config.example | 配置风格不友好 |
rabbitmq-env.conf (rabbitmq-env.conf.bat on Windows) | /etc/rabbitmq/rabbitmq-env.conf | 同rabbitmq.conf 风格 | 与系统环境变量不同的是配置项Key无RABBITMQ_ 前缀。 |
- 更改数据目录
注意:
- 一定要关闭selinux
- 修改rabbitmq-env.conf文件时,注意节点名
NODENAME
和数据库目录MNESIA_DIR
要根据实际情况修改。
ls -al /var/lib/rabbitmq/mnesia
mkdir -p /home/data/rabbitmq
mv /var/lib/rabbitmq/mnesia /home/data/rabbitmq/
chown -R rabbitmq:rabbitmq /home/data/rabbitmq
方式1.通过环境变量指定数据目录
cat >> /etc/profile << \EOF
RABBITMQ_NODENAME=rabbit@$HOSTNAME
RABBITMQ_MNESIA_BASE=/home/data/rabbitmq/mnesia
RABBITMQ_MNESIA_DIR=$RABBITMQ_MNESIA_BASE/$RABBITMQ_NODENAME
export RABBITMQ_NODENAME RABBITMQ_MNESIA_BASE RABBITMQ_MNESIA_DIR
EOF
source /etc/profile
方式2.通过rabbitmq-env.con
指定数据目录
cat >> /etc/rabbitmq/rabbitmq-env.conf << \EOF
NODENAME=rabbit@rabbit-node3
MNESIA_BASE=/home/data/rabbitmq/mnesia
MNESIA_DIR=/home/data/rabbitmq/mnesia/rabbit@rabbit-node3
EOF
五、haproxy安装和配置
1.安装
yum -y install gcc automake autoconf libtool make
wget -c https://src.fedoraproject.org/repo/pkgs/haproxy/haproxy-2.4.8.tar.gz/sha512/8e1d28191a8c26d46989359a213444f30a09e439d32b5ab6cb01a3ca267788fc7677dd14deaa43a7f6c7741cbf6c8fcf6cdd5cf927d23e48f82b9e7723d8a6f9/haproxy-2.4.8.tar.gz
tar -zxvf haproxy-2.4.8.tar.gz
cd haproxy-2.4.8
make TARGET=linux-glibc PREFIX=/usr/local/haproxy-2.4.8
make install PREFIX=/usr/local/haproxy-2.4.8
cat >> /etc/profile <<\EOF
export HAPROXY_HOME=/usr/local/haproxy-2.4.8
export PATH=$PATH:$HAPROXY_HOME/sbin
EOF
source /etc/profile
haproxy -v
2.配置
mkdir /etc/haproxy
cat >> /etc/haproxy/haproxy.cfg << \EOF
# 全局配置
global
# 日志输出配置、所有日志都记录在本机,通过 local0 进行输出
log 127.0.0.1 local0 info
# 最大连接数
maxconn 4096
# 改变当前的工作目录
chroot /usr/local/haproxy-2.4.8
# 以指定的 UID 运行 haproxy 进程
uid 99
# 以指定的 GID 运行 haproxy 进程
gid 99
# 以守护进行的方式运行
daemon
# 当前进程的 pid 文件存放位置
pidfile /usr/local/haproxy-2.4.8/haproxy.pid
# 默认配置
defaults
# 应用全局的日志配置
log global
# 使用4层代理模式,7层代理模式则为"http"
mode tcp
# 日志类别
option tcplog
# 不记录健康检查的日志信息
option dontlognull
# 3次失败则认为服务不可用
retries 3
# 每个进程可用的最大连接数
maxconn 2000
# 连接超时
timeout connect 5s
# 客户端超时
timeout client 120s
# 服务端超时
timeout server 120s
# 绑定配置
listen rabbitmq_cluster
bind :5671
# 配置TCP模式
mode tcp
# 采用加权轮询的机制进行负载均衡
balance roundrobin
# RabbitMQ 集群节点配置
server mq-node1 rabbit-node1:5672 check inter 5000 rise 2 fall 3 weight 1
server mq-node2 rabbit-node2:5672 check inter 5000 rise 2 fall 3 weight 1
server mq-node3 rabbit-node3:5672 check inter 5000 rise 2 fall 3 weight 1
# 绑定配置
listen rabbitmq_cluster_ma
bind :15671
# 配置TCP模式
mode tcp
# 采用加权轮询的机制进行负载均衡
balance roundrobin
# RabbitMQ 集群节点配置
server mq-node1 rabbit-node1:15672 check inter 5000 rise 2 fall 3 weight 1
server mq-node2 rabbit-node2:15672 check inter 5000 rise 2 fall 3 weight 1
server mq-node3 rabbit-node3:15672 check inter 5000 rise 2 fall 3 weight 1
# 配置监控页面
listen monitor
bind :8100
mode http
option httplog
stats enable
stats uri /stats
stats refresh 5s
EOF
3.启动和关闭
haproxy -f /etc/haproxy/haproxy.cfg
ps aux|grep haproxy
killall haproxy
4.开机启动
cat >> /etc/rc.local << \EOF
/usr/local/haproxy-2.4.8/sbin/haproxy -f /etc/haproxy/haproxy.cfg
EOF
5.防火墙配置
firewall-cmd --zone=public --add-port=5671/tcp --permanent
firewall-cmd --zone=public --add-port=15671/tcp --permanent
firewall-cmd --zone=public --add-port=8100/tcp --permanent
firewall-cmd --reload
6.访问
六、keepalived安装和配置
KeepAlived 采用
VRRP
(Virtual Router Redundancy Protocol,虚拟路由冗余协议) 来解决单点失效的问题,它通常由一组一备两个节点组成,同一时间内只有主节点会提供对外服务,并同时提供一个虚拟的 IP 地址 (Virtual Internet Protocol Address ,简称 VIP) 。若主节点
keepalived
服务关闭,则VIP自动漂移到备用节点上,等待主节点keepalived
服务恢复后,则自动漂移回主节点上(可通过ip addr
命令查看当前VIP所在节点位置)。基于此种情况,一般建议主节点的机器整体性能不低于备用节点。
1.安装
keepalived依赖postfix,postfix依赖
libmysqlclient.so.18()(64bit)
,默认情况下,该库文件是存在的(mariadb-lib提供),若安装mysql是将其卸载而来,需要对应的安装mysql-community-libs-compat
兼容lib包,然后重启动相关服务(例如systemctl restart postfix
),建议重启下操作系统。
yum -y install keepalived
2.配置
注意以下几点
- state 角色为 BACKUP
- interface 为网卡的 ID,要根据机器确认
- virtual_route_id 要与 MASTER 一致,默认为 51
- priority 要比 MASTER 小
- unicast_src_ip 要设置正确,组播地址设置之后,要注释 vrrp_strict 选项。
- 主节点
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
cat > /etc/keepalived/keepalived.conf << \EOF
global_defs {
# 路由id,主备节点不能相同
router_id node1
notification_email {
# email 接收方
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# email 发送方
notification_email_from Alexandre.Cassen@firewall.loc
# 邮件服务器, smtp 协议
smtp_server 192.168.200.1
smtp_connect_timeout 30
vrrp_skip_check_adv_addr
# 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
#vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
# 自定义监控脚本
vrrp_script chk_haproxy {
# 脚本位置
script "/etc/keepalived/haproxy_check.sh"
# 脚本执行的时间间隔
interval 5
weight 10
}
vrrp_instance VI_1 {
# Keepalived的角色,MASTER 表示主节点,BACKUP 表示备份节点
state MASTER
# 指定监测的网卡,可以使用 ifconfig 进行查看
interface eth0
# 虚拟路由的id,主备节点需要设置为相同
virtual_router_id 51
# 优先级,主节点的优先级需要设置比备份节点高
priority 100
# 设置主备之间的检查时间,单位为秒
advert_int 1
# 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
unicast_src_ip 192.168.63.17
unicast_peer {
192.168.63.19
}
# 定义验证类型和密码
authentication {
auth_type PASS
auth_pass 123456
}
# 调用上面自定义的监控脚本
track_script {
chk_haproxy
}
virtual_ipaddress {
# 虚拟IP地址,可以设置多个
192.168.63.200/24 brd 192.168.63.255
}
}
EOF
- 备节点
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
cat > /etc/keepalived/keepalived.conf << \EOF
global_defs {
# 路由id,主备节点不能相同
router_id node2
notification_email {
# email 接收方
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# email 发送方
notification_email_from Alexandre.Cassen@firewall.loc
# 邮件服务器, smtp 协议
smtp_server 192.168.200.1
smtp_connect_timeout 30
vrrp_skip_check_adv_addr
# 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
#vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script chk_haproxy {
script "/etc/keepalived/haproxy_check.sh"
interval 5
weight 10
}
vrrp_instance VI_1 {
# BACKUP 表示备份节点
state BACKUP
# 指定监测的网卡
interface eth0
# 虚拟路由的id,主备节点需要设置为相同
virtual_router_id 51
# 优先级,备份节点要比主节点低
priority 50
advert_int 1
# 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
unicast_src_ip 192.168.63.19
unicast_peer {
192.168.63.17
}
authentication {
auth_type PASS
auth_pass 123456
}
track_script {
chk_haproxy
}
virtual_ipaddress {
192.168.63.200/24 brd 192.168.63.255
}
}
EOF
- 监测脚本(主、备)
cat > /etc/keepalived/haproxy_check.sh << \EOF
#!/bin/bash
# 判断haproxy是否已经启动
if [ ${ps -C haproxy --no-header |wc -l} -eq 0 ] ; then
#如果没有启动,则启动
haproxy -f /etc/haproxy/haproxy.cfg
fi
#睡眠3秒以便haproxy完全启动
sleep 3
#如果haproxy还是没有启动,此时需要将本机的keepalived服务停掉,以便让VIP自动漂移到另外一台haproxy
if [ ${ps -C haproxy --no-header |wc -l} -eq 0 ] ; then
systemctl stop keepalived
fi
EOF
chmod +x /etc/keepalived/haproxy_check.sh
- IP转发
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
sysctl -p
- 日志配置
修改
/etc/sysconfig/keepalived
,把 KEEPALIVED_OPTIONS="-D" 修改为 KEEPALIVED_OPTIONS="-D -d -S 0",其中 -S 指定 syslog 的 facility修改
/etc/rsyslog.conf
末尾添加
vim /etc/sysconfig/keepalived
# Options for keepalived. See `keepalived --help' output and keepalived(8) and
# keepalived.conf(5) man pages for a list of all options. Here are the most
# common ones :
#
# --vrrp -P Only run with VRRP subsystem.
# --check -C Only run with Health-checker subsystem.
# --dont-release-vrrp -V Dont remove VRRP VIPs & VROUTEs on daemon stop.
# --dont-release-ipvs -I Dont remove IPVS topology on daemon stop.
# --dump-conf -d Dump the configuration data.
# --log-detail -D Detailed log messages.
# --log-facility -S 0-7 Set local syslog facility (default=LOG_DAEMON)
#
# KEEPALIVED_OPTIONS="-D"
KEEPALIVED_OPTIONS="-D -d -S 0"
cat >> /etc/rsyslog.conf << \EOF
local0.* /var/log/keepalived.log
EOF
systemctl restart rsyslog
3.启动和关闭
systemctl start keepalived
systemctl status keepalived
systemctl stop keepalived
4.开机启动
systemctl enable keepalived
5.查看
ip addr
转载: