RabbitMQ 有 3 种模式,其中 2 种是集群模式。
单一模式:即单机情况不做集群,就单独运行一个 RabbitMQ 而已。
普通模式:默认模式,以两个节点(A、B)为例来进行说明:
镜像模式 :经典的 Mirror 镜像模式,保证数据不丢失:
另外,还有主备模式,远程模式,多活模式等等。
前置条件:准备两台 linux(192.168.186.128 和 192.168.186.129),并安装好 RabbitMQ。
1. 修改映射文件 vim /etc/hosts 。
1 号服务器:
127.0.0.1 A localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 A localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.186.128 A
192.168.186.129 B
2 号服务器:
127.0.0.1 A localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 A localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.186.128 A
192.168.186.129 B
修改完 hosts 文件后,需要重启 Linux 服务器 reboot,否则配置不生效。
2. 相互通信,cookie 必须保持一致,同步 RabbitMQ 的 cookie 文件:跨服务器拷贝 .erlang.cookie(隐藏文件,使用 ls -all 显示)。
scp /var/lib/rabbitmq/.erlang.cookie 192.168.186.129:/var/lib/rabbitmq/
修改 cookie 文件,要重启 linux 服务器 reboot。
3. 防火墙开放 epmd 端口 4369,启动 RabbitMQ 服务。
firewall-cmd --zone=public --add-port=4369/tcp --permanent
firewall-cmd --reload
systemctl start rabbitmq-server
4. 加入集群节点,节点 A 加入 节点 B,或者节点 B 加入节点 A 都可以:
[root@A ~]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@A ...
[root@A ~]# rabbitmqctl join_cluster rabbit@B
Clustering node rabbit@A with rabbit@B
[root@A ~]# rabbitmqctl start_app
Starting node rabbit@A ...
5. 查看节点状态:
rabbitmqctl cluster_status
6. 查看管理端
搭建集群结构之后,之前创建的交换机、队列、用户都属于单一结构,在新的集群环境中是不能用的。
所以在新的集群中重新手动添加用户即可(任意节点添加,所有节点共享)。
[root@A ~]# rabbitmqctl add_user zm 123456
Adding user "zm" ...
[root@A ~]# rabbitmqctl set_user_tags zm administrator
Setting tags for user "zm" to [adminstrator] ...
[root@A ~]# rabbitmqctl set_permissions -p "/" zm ".*" ".*" ".*"
Setting permissions for user "zm" in vhost "/" ...
[root@A ~]# rabbitmqctl list_users
Listing users ...
user tags
zm [administrator]
guest [administrator]
访问 http://192.168.186.128:15672 和 http://192.168.186.129:15672,两个节点共享用户。
注意:当节点脱离集群还原成单一结构后,交换机,队列和用户等数据都会重新回来。
此时,RabbitMQ 的集群搭建完毕,但是默认采用的模式为“普通模式”,可靠性不高。
将所有队列设置为镜像队列,即队列会被复制到各个节点,各个节点状态一致。
语法:set_policy {NAME} {PATTERN} {DEFINITION}
其中:NAME
- 策略名,可自定义
PATTERN
- 队列的匹配模式(正则表达式)
DEFINITION
- 镜像定义,包括三个部分 ha-mode, ha-params, ha-sync-mode
[root@A ~]# rabbitmqctl set_policy policy_renda "^" '{"ha-mode":"all"}'
Setting policy "policy_zm" for pattern "^" to "{"ha-mode":"all"}" with priority "0" for vhost "/" ...
通过管理端 Admin
-> Policies
-> Add / update a policy
设置镜像策略。
设置好镜像模式后,在节点 A 增加了队列后,节点 B 也可以看到新增的队列。
在 RabbitMQ 管理界面 Admin
-> Virtual Hosts
-> Add a new virtual host
创建虚拟主机 /zm;
使用 Spring 整合的 RabbitMQ 重新测试发送和接受消息;在其中一个节点使用命令 rabbitmqctl stop_app 停掉,再测试,仍然可以发送和接受消息。
虽然在程序中访问 A 服务器,可以实现消息的同步,但都是 A 服务器在接收消息,A 太累;是否可以负载均衡,A 和 B 轮流接收消息,再镜像同步。
HA - High Available 高可用,Proxy - 代理。
HAProxy 是一款提供高可用性,负载均衡,并且基于 TCP 和 HTTP 应用的代理软件。
HAProxy 完全免费。
HAProxy 可以支持数以万计的并发连接。
HAProxy 可以简单又安全的整合进架构中,同时还保护 Web 服务器不被暴露到网络上。
生产者 -- 投递消息 --> HAProxy
消费者 -- 订阅消息 --> HAProxy
HAProxy ---> [MQ Node 1, MQ Node 2, MQ Node 3]
OSI - Open System Interconnection 开放式系统互联,是把网络通信的工作分为 7 层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
Nginx 的优点:
HAProxy 的优点:
性能上 HAProxy 胜,但是功能性和便利性上 Nginx 胜。
对于 Http 协议,HAProxy 处理效率比 Nginx 高;所以,没有特殊要求的时候或者一般场景,建议使用 Haproxy 来做 Http 协议负载;如果是 Web 应用,建议使用 Nginx。
需要结合使用场景的特点来进行合理地选择。
HAProxy 下载:http://www.haproxy.org/download/1.8/src/haproxy-1.8.12.tar.gz
tar -zxvf haproxy-1.8.12.tar.gz
make
时需要使用 TARGET 指定内核及版本:[root@localhost haproxy-1.8.12]# uname -r
3.10.0-229.el7.x86_64
查看目录下的 README 文件 less /opt/haproxy-1.8.12/README 可知需要根据内核版本选择编译参数:
...
To build haproxy, you have to choose your target OS amongst the following ones
and assign it to the TARGET variable :
- linux22 for Linux 2.2
- linux24 for Linux 2.4 and above (default)
- linux24e for Linux 2.4 with support for a working epoll (> 0.21)
- linux26 for Linux 2.6 and above
- linux2628 for Linux 2.6.28, 3.x, and above (enables splice and tproxy)
- solaris for Solaris 8 or 10 (others untested)
- freebsd for FreeBSD 5 to 10 (others untested)
- netbsd for NetBSD
- osx for Mac OS/X
- openbsd for OpenBSD 5.7 and above
- aix51 for AIX 5.1
...
cd /opt/haproxy-1.8.12/
make TARGET=linux2628 PREFIX=/usr/local/haproxy
make install PREFIX=/usr/local/haproxy
[root@localhost haproxy-1.8.12]# /usr/local/haproxy/sbin/haproxy -v
HA-Proxy version 1.8.12-8a200c7 2018/06/27
Copyright 2000-2018 Willy Tarreau
cp /usr/local/haproxy/sbin/haproxy /usr/sbin/
cp /opt/haproxy-1.8.12/examples/haproxy.init /etc/init.d/haproxy
chmod 755 /etc/init.d/haproxy
useradd -r haproxy
mkdir /etc/haproxy
vim /etc/haproxy/haproxy.cfg
# 全局配置
global
# 设置日志
log 127.0.0.1 local0 info
# 当前工作目录
chroot /usr/local/haproxy
# 用户与用户组
user haproxy
group haproxy
# 运行进程 ID
uid 99
gid 99
# 守护进程启动
daemon
# 最大连接数
maxconn 4096
# 默认配置
defaults
# 应用全局的日志配置
log global
# 默认的模式 mode {tcp|http|health},TCP 是 4 层,HTTP 是 7 层,health 只返回 OK
mode tcp
# 日志类别 tcplog
option tcplog
# 不记录健康检查日志信息
option dontlognull
# 3 次失败则认为服务不可用
retries 3
# 每个进程可用的最大连接数
maxconn 2000
# 连接超时
timeout connect 5s
# 客户端超时 30 秒,ha 就会发起重新连接
timeout client 30s
# 服务端超时 15 秒,ha 就会发起重新连接
timeout server 15s
# 绑定配置
listen rabbitmq_cluster
bind 192.168.186.130:5672
# 配置 TCP 模式
mode tcp
# 简单的轮询
balance roundrobin
# RabbitMQ 集群节点配置,每隔 5 秒对 mq 集群做检查,2 次正确证明服务可用,3 次失败证明服务不可用
server A 192.168.186.128:5672 check inter 5000 rise 2 fall 3
server B 192.168.186.129:5672 check inter 5000 rise 2 fall 3
# haproxy 监控页面地址
listen monitor
bind 192.168.186.130:8100
mode http
option httplog
stats enable
# 监控页面地址 http://192.168.186.130:8100/monitor
stats uri /monitor
stats refresh 5s
service haproxy start
firewall-cmd --zone=public --add-port=5672/tcp --permanent
firewall-cmd --zone=public --add-port=8100/tcp --permanent
firewall-cmd --reload
项目发消息,只需要将服务器地址修改为 192.168.186.130
即可,其余不变。
这样,所有的请求都会交给 HAProxy,然后它会负载均衡地发给每个 RabbitMQ 服务器。
如果 HAProxy 服务器宕机,RabbitMQ 服务器就不可用了,所以对 HAProxy 也要做高可用的集群。
Keepalived 是 Linux 的轻量级别的高可用热备解决方案。
Keepalived 的作用是检测服务器的状态,它根据 TCP / IP 参考模型的第三层、第四层、第五层交换机制检测每个服务节点的状态,如果有一台 web 服务器宕机,或工作出现故障,Keepalived 将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后 Keepalived 自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。
Keepalived 基于 VRRP - Virtual Router Redundancy Protocol 虚拟路由冗余协议协议;VRRP 是一种主备(主机和备用机)模式的协议,通过 VRRP 可以在网络发生故障时透明的进行设备切换而不影响主机之间的数据通信。
两台主机之间生成一个虚拟的 ip,称为漂移 ip,漂移 ip 由主服务器承担,一但主服务器宕机,备份服务器就会抢夺漂移 ip,继续工作,有效的解决了群集中的单点故障。
KeepAlived 将多台路由器设备虚拟成一个设备,对外提供统一 ip(Virtual IP)。
生产者 -- 投递消息 --> KeepAlived
消费者 -- 订阅消息 --> KeepAlivedHAProxy 1 --> 主机 1 --> KeepAlived 虚拟 IP
HAProxy 2 --> 主机 2 --> KeepAlived 虚拟 IP
3 号服务器 192.168.186.130:
127.0.0.1 C localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 C localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.186.128 A
192.168.186.129 B
192.168.186.130 C
192.168.186.131 D
4 号服务器 192.168.186.131:
127.0.0.1 D localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 D localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.186.128 A
192.168.186.129 B
192.168.186.130 C
192.168.186.131 D
注意:修改完 hosts 文件后,需要重启 Linux 服务器 reboot,否则配置不生效。
service haproxy start
yum install -y keepalived
rm -rf /etc/keepalived/keepalived.conf
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
# 非常重要,标识本机的 hostname
router_id C
}
vrrp_script chk_haproxy {
# 执行的脚本位置
script "/etc/keepalived/haproxy_check.sh"
# 检测时间间隔
interval 2
# 如果条件成立则权重减 20
weight -20
}
vrrp_instance VI_1 {
# 非常重要,标识主机,备用机 131 改为 BACKUP
state MASTER
# 非常重要,网卡名(ifconfig 查看)
interface ens33
# 非常重要,自定义,虚拟路由 ID 号(主备节点要相同)
virtual_router_id 66
# 优先级(0-254),一般主机的大于备机
priority 100
# 主备信息发送间隔,两个节点必须一致,默认 1 秒
advert_int 1
# 认证匹配,设置认证类型和密码,MASTER 和 BACKUP 必须使用相同的密码才能正常通信
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
# 检查 haproxy 健康状况的脚本
chk_haproxy
}
# 简称 “VIP”
virtual_ipaddress {
# 非常重要,虚拟 ip,可以指定多个,以后连接 mq 就用这个虚拟ip
192.168.186.66/24
}
}
# 虚拟 ip 的详细配置
virtual_server 192.168.186.66 5672 {
# 健康检查间隔,单位为秒
delay_loop 6
# lvs 调度算法 rr|wrr|lc|wlc|lblc|sh|dh
lb_algo rr
# 负载均衡转发规则。一般包括 DR, NAT, TUN 3 种
lb_kind NAT
# 转发协议,有 TCP 和 UDP 两种,一般用 TCP
protocol TCP
# 本机的真实 ip
real_server 192.168.186.130 5672 {
# 默认为 1, 失效为 0
weight 1
}
}
vim /etc/keepalived/haproxy_check.sh
#!/bin/bash
COUNT=`ps -C haproxy --no-header |wc -l`
if [ $COUNT -eq 0 ];then
/usr/local/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg
sleep 2
if [ `ps -C haproxy --no-header |wc -l` -eq 0 ];then
killall keepalived
fi
fi
Keepalived 组之间的心跳检查并不能察觉到 HAproxy 负载是否正常,所以需要使用此脚本。在 Keepalived 主机上,开启此脚本检测 HAproxy 是否正常工作,如正常工作,记录日志。如进程不存在,则尝试重启 HAproxy ,2 秒后检测,如果还没有,则关掉主机的 Keepalived ,此时备 Keepalived 检测到主 Keepalived 挂掉,接管 VIP,继续服务。
chmod +x /etc/keepalived/haproxy_check.sh
此时,安装完毕,按照上面的步骤就可以安装第二台主机 D 了(服务器 hostname 和 ip 注意要修改)。
service keepalived start | stop | status | restart
service keepalived start
ps -ef | grep haproxy
ps -ef | grep keepalived
启动 keepalived 前的情况:
[root@C keepalived]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:ac:93:50 brd ff:ff:ff:ff:ff:ff
inet 192.168.186.130/24 brd 192.168.186.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feac:9350/64 scope link
valid_lft forever preferred_lft forever
启动 keepalived 后的情况:
[root@C keepalived]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:ac:93:50 brd ff:ff:ff:ff:ff:ff
inet 192.168.186.130/24 brd 192.168.186.255 scope global ens33
valid_lft forever preferred_lft forever
inet 192.168.186.66/24 scope global secondary ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feac:9350/64 scope link
valid_lft forever preferred_lft forever
可以看到 ens33 网卡还多绑定了一个 IP 地址。
常见的网络错误:子网掩码、网关等信息要一致。
测试 vip 和端口一起是否能提供服务
在 192.168.186.128,A 服务器上测试。
在服务器 A 执行 curl 192.168.186.130:5672
和 curl 192.168.186.66:5672
都能正常返回 AMPQ,说明安装成功。
测试 ip 漂移的规则
使用 ip addr 或 ip a 查看虚拟 ip。
刚开始时,C 和 D 都启动了 KeepAlived;C 是主机,所以虚拟 ip 在主机 C,表现为主机 C 显示 inet 192.168.186.66/24
,而备机 D 不显示。
然后,停止主机 C 的 keepalived service keepalived stop
,虚拟 ip 漂移到 D 节点,D 节点执行 ip a 可以看到 inet 192.168.186.66/24
,而主机 C 却不显示。
接着,重新启动 C 节点的 Keepalived,虚拟 ip 依旧在 D 节点,并不会由于 C 的回归而回归。
最后,停止 D 的 Keepalived,虚拟 ip 再漂移回 C 节点。
测试项目发消息
消费者或生产者 -- 漂移 IP 66 --> KeepAlived 服务 --> [HAProxy 服务器C 130, HAProxy 服务器D 131]
HAProxy 服务器C 130 -- 负载均衡 --> [MQ 服务器A 128, MQ 服务器B 129]
HAProxy 服务器D 130 -- 负载均衡 --> [MQ 服务器A 128, MQ 服务器B 129]
测试单个 RabbitMQ 服务器:将服务器地址修改为 192.168.186.128,其余不变。
测试 HAProxy 实现多个 RabbitMQ 服务器负载均衡:将服务器地址修改为 192.168.186.130,其余不变。
测试 KeepAlived 实现的高可用的 HAProxy 集群:将服务器地址修改为 KeepAlived 的虚拟 IP 192.168.186.66,其余不变。