本教程是RabbitMQ系列教程的延续;搭建环境在之前的基础之上。
1、搭建集群
1)克隆三台虚拟机
2)SSH连接
3)修改hostname名称
三台机器分别为node1、node2、node3
不同的系统修改方法不同,CentOS7修改方法:
- 命令修改
# 修改
hostnamectl set-hostname node1
# 重启
reboot
- 文件修改
# 修改文件
vim /etc/hostname
# 删除或注释掉原来的,在前面加上node1
node1
# localhost.localdomain
# 退出保存
# 重启
reboot
4)修改hosts文件
修改每台机器的
/etc/hosts
文件,让各个节点都能互相识别对象
vim /etc/hosts
# 添加
192.168.19.102 node1
192.168.19.103 node2
192.168.19.104 node3
5)同步cookie文件
以确保各个节点的cookie文件使用的是同一个值:在 node1上执行远程操作命令
scp /var/lib/rabbitmq/.erlang.cookie root@node2:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie root@node3:/var/lib/rabbitmq/.erlang.cookie
6)启动RabbitMQ服务
顺带启动Erlang虚拟机和RabbitMQ应用服务;三个节点都执行
rabbitmq-server -detached
7)节点2加入节点1
# rabbitmqctl stop 会将Erlang虚拟机关闭 rabbitmqctl stop_app 只关闭rabbitmq服务
rabbitmqctl stop_app
# 重置
rabbitmqctl reset
# 加入节点1
rabbitmqctl join_cluster rabbit@node1
# 只启动rabbitmq服务
rabbitmqctl start_app
出现端口未开启问题,端口开启后继续执行
- 开启
4369
、25672
端口,并重启防火墙;三个节点都分别开启
# 开启防火墙 4369 端口
firewall-cmd --zone=public --add-port=4369/tcp --permanent
# 开启防火墙 25672 端口
firewall-cmd --zone=public --add-port=25672/tcp --permanent
# 重启
systemctl restart firewalld.service
- 继续执行节点2加入节点1
8)节点3加入节点2
# 停止服务
rabbitmqctl stop_app
# 重置
rabbitmqctl reset
# 加入节点2
rabbitmqctl join_cluster rabbit@node2
# 启动服务
rabbitmqctl start_app
9)查看集群状态
# 可以在任一节点下查看
rabbitmqctl cluster_status
10)设置用户
# 在任一节点下设置即可
# 创建账号
rabbitmqctl add_user admin admin
# 设置用户角色
rabbitmqctl set_user_tags admin administrator
# 设置用户权限
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
11)web界面
12)集群的关闭与重启
没有一个直接的命令可以关闭整个集群,需要逐一进行关闭。但是需要保证在重启时,最后关闭的节点最先被启动。如果第一个启动的不是最后关闭的节点,那么这个节点会等待最后关闭的那个节点启动,默认进行 10 次连接尝试,超时时间为 30 秒,如果依然没有等到,则该节点启动失败。
这带来的一个问题是,假设在一个三节点的集群当中,关闭的顺序为 node1,node2,node3,如果 node1 因为故障暂时没法恢复,此时 node2 和 node3 就无法启动。想要解决这个问题,可以先将 node1 节点进行剔除,命令如下:
rabbitmqctl forget_cluster_node rabbit@node1 --offline
此时需要加上 -offline
参数,它允许节点在自身没有启动的情况下将其他节点剔除。
13)解除节点
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
rabbitmqctl cluster_status
# 此项命令在node1上执行;node1 忘掉 node2,即 node2 脱离 node1
rabbitmqctl forget_cluster_node rabbit@node2
2、镜像队列
1)使用镜像的原因
如果 RabbitMQ 集群中只有一个Broker节点,那么该节点的失效将导致整体服务的临时性不可用,并且也可能会导致消息的丢失。可以将所有消息都设置为持久化,并且对应队列的durable属性也设置为true,但是这样仍然无法避免由于缓存导致的问题:因为消息在发送之后和被写入磁盘并执行刷盘动作之间,存在一个短暂却会产生问题的时间窗。通过发布确认机制能够确保客户端知道哪些消息己经存入磁盘,尽管如此,一般不希望遇到因单点故障导致的服务不可用。
引入镜像队列(Mirror Queue)的机制,可以将队列镜像到集群中的其他Broker节点之上;如果集群中的一个节点失效了,队列能自动地切换到镜像中的另一个节点上以保证服务的可用性。
2)搭建步骤
(1)启动三台集群节点
(2)随便找一个节点添加policy
(3)测试
- 生产者:向节点node1(192.168.19.102)发送消息
package com.tuwer.rabbitmq.simple;
import com.rabbitmq.client.*;
import com.tuwer.utils.RabbitMqUtils;
import java.io.IOException;
import java.time.LocalDateTime;
/**
* @author 土味儿
* Date 2022/3/23
* @version 1.0
* -------------
* 生产者
* 供应商(provider)
*/
public class Producer {
public static void main(String[] args) {
// 工具类
RabbitMqUtils mqUtils = new RabbitMqUtils();
// 获取通道
Channel channel = mqUtils.getChannel(
"192.168.19.102",
5672,
"admin",
"admin",
"/",
"生产者");
try {
// 通过通道声明队列queue存储消息
//String queueName = "queue1";
String queueName = "mirror.queue";
channel.queueDeclare(queueName, false, false, false, null);
// 准备消息
String message = "Hello World! " + LocalDateTime.now();
// 发送消息
channel.basicPublish("", queueName, null, message.getBytes());
System.out.println("消息发送成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭
mqUtils.close();
}
}
}
- 关闭node1
- 消费者接收消息:只能从 node2 或 node3 接收
- 配置了镜像队列后,向任何一个节点发送消息,都可以从任何一个节点接收,只要该节点可以访问
- 节点重新启动后,需要重启服务
systemctl start rabbitmq-server
,或者设置为 开机启动服务systemctl enable rabbitmq-server
3、负载均衡 HAProxy
1)HAProxy 介绍
- 免费、快速并且可靠
- HAProxy 是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。
- HAProxy 特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
- HAProxy 实现了一种
事件驱动
,单一进程
模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户空间(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。 - 包括 GitHub、Bitbucket、Stack Overflow、Reddit、Tumblr、Twitter和 Tuenti在内的知名网站,及亚马逊网络服务系统都使用了HAProxy。
2)安装运行架构图
3)安装
yum 源安装目前版本比较低,采用源码安装方式。
- 下载依赖包
# gcc c语言环境
# vim 编辑器
# wget 下载工具
yum install gcc vim wget
- 下载安装包
haproxy-2.5.5.tar.gz
下载地址:https://www.haproxy.org/#down
- 上传安装包
可以上传至任意目录下。此处上传到home目录下
[root@node1 /]# cd home
[root@node1 home]# rz
[root@node1 home]# ls
haproxy-2.5.5.tar.gz
- 解压安装包
tar -zxvf haproxy-2.5.5.tar.gz -C /usr/local
-
编译、安装
在安装根目录下执行,即
/usr/local/haproxy-2.5.5
# 编译
make TARGET=linux-glibc PREFIX=/usr/local/haproxy-2.5.5
# 安装
make install PREFIX=/usr/local/haproxy-2.5.5
- 配置环境变量
vim /etc/profile
# 在文件最后加上
export HAPROXY_HOME=/usr/local/haproxy-2.5.5
export PATH=$PATH:$HAPROXY_HOME/sbin
使配置的环境变量立即生效:
# 方式一
source /etc/profile
# 方式二
. /etc/profile
- 负载均衡配置
新建配置文件 haproxy.cfg
,位置为:/etc/haproxy/haproxy.cfg
# 创建目录
mkdir /etc/haproxy
# 编辑文件内容
vim /etc/haproxy/haproxy.cfg
文件内容:
# 全局配置
global
# 日志输出配置、所有日志都记录在本机,通过 local0 进行输出
log 127.0.0.1 local0 info
# 最大连接数
maxconn 4096
# 改变当前的工作目录
chroot /usr/local/haproxy-2.5.5
# 以指定的 UID 运行 haproxy 进程
uid 99
# 以指定的 GID 运行 haproxy 进程
gid 99
# 以守护进程的方式运行
daemon
# 当前进程的 pid 文件存放位置
pidfile /usr/local/haproxy-2.5.5/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 :192.168.19.102:5671
bind :5671
# 配置TCP模式
mode tcp
# 采用加权轮询的机制进行负载均衡
balance roundrobin
# RabbitMQ 集群节点配置
server mq-node1 node1:5672 check inter 5000 rise 2 fall 3 weight 1
server mq-node2 node2:5672 check inter 5000 rise 2 fall 3 weight 1
server mq-node3 node3:5672 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
负载均衡的主要配置在 listen rabbitmq_cluster
下,这里指定负载均衡的方式为加权轮询,同时定义好健康检查机制:
server node1 rabbit-node1:5672 check inter 5000 rise 2 fall 3 weight 1
以上配置代表对地址为 node1:5672
的 node1 节点每隔 5 秒进行一次健康检查,如果连续两次的检查结果都是正常,则认为该节点可用,此时可以将客户端的请求轮询到该节点上;如果连续 3 次的检查结果都不正常,则认为该节点不可用。weight
用于指定节点在轮询过程中的权重。
4)启动服务
# 启动
haproxy -f /etc/haproxy/haproxy.cfg
# 查看运行
ps aux|grep haproxy
# 停止 没有killall命令, 安装yum -y install psmisc
killall haproxy
- 开启端口:
5671
8100
# 开启监控端口:8100
firewall-cmd --zone=public --add-port=8100/tcp --permanent
# 开启服务端口:5671
firewall-cmd --zone=public --add-port=5671/tcp --permanent
# 重启防火墙
systemctl restart firewalld.service
- 打开监控页面
所有节点都为绿色,代表节点健康。此时证明 HAProxy 搭建成功,并已经对 RabbitMQ 集群进行监控。
5)测试
由于HAProxy是安装node1下,所以生产者和消费者可以访问
192.168.19.102:5671
;记着开启5671
端口
- 生产者发消息
- 消费者接收消息
-
关闭两个节点测试
关闭node1和node3中的rabbitmq服务
rabbitmqctl stop_app
node1节点中运行有mq服务,也有HAProxy服务,只关闭mq服务
-
重启node3节点
rabbitmqctl start_app
重启前发送一条消息,放在队列中不去消费,观察镜像的备份变化
至此HAProxy安装完成!但是现在严重依赖于node1,如果node1挂掉了,整个集群也就挂掉了…
4、故障转移 Keepalived
搭建Keepalived前,把HAProxy也安装在node2上,配置与node1类似
接着就可以搭建 Keepalived 来解决 HAProxy 故障转移的问题。这里在 node1 和 node2 上安装 KeepAlived ,两台主机上的搭建的步骤完全相同,只是部分配置略有不同,具体如下:
环境说明
Name | IP Addr | Service Name | Descprition |
---|---|---|---|
VIP | 192.168.19.100 | 虚拟 IP | |
MASTER | 192.168.19.102 | node1 | 主服务器 IP |
BACKUP | 192.168.19.103 | node2 | 备服务器 IP |
1)安装运行架构图
- 简略图
2)安装
Keepalived 可以使用 yum 直接安装,在 MASTER 服务器和 BACKUP 服务器执行:
yum -y install keepalived
3)配置 MASTER 和 BACKUP
(1)确认网卡
ip a
(2)MASTER 节点配置
vim /etc/keepalived/keepalived.conf
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 ens32
# 虚拟路由的id,主备节点需要设置为相同
virtual_router_id 51
# 优先级,主节点的优先级需要设置比备份节点高
priority 100
# 设置主备之间的检查时间,单位为秒
advert_int 1
# 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
unicast_src_ip 192.168.19.102
unicast_peer {
192.168.19.103
}
# 定义验证类型和密码
authentication {
auth_type PASS
auth_pass 000000
}
# 调用上面自定义的监控脚本
track_script {
chk_haproxy
}
virtual_ipaddress {
# 虚拟IP地址,可以设置多个
192.168.19.100
}
}
(3)BACKUP 节点配置
备份节点的配置与主节点基本相同,但是需要修改其 state 为 BACKUP;同时其优先级 priority 需要比主节点低。
vim /etc/keepalived/keepalived.conf
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 ens32
# 虚拟路由的id,主备节点需要设置为相同
virtual_router_id 51
# 优先级,备份节点要比主节点低
priority 50
# 设置主备之间的检查时间,单位为秒
advert_int 1
# 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
unicast_src_ip 192.168.19.103
unicast_peer {
192.168.19.102
}
authentication {
auth_type PASS
auth_pass 000000
}
track_script {
chk_haproxy
}
virtual_ipaddress {
192.168.19.100
}
}
注意以下几点
- state 角色为 BACKUP
- interface 为网卡的 ID,要根据机器确认
- virtual_route_id 要与 MASTER 一致,默认为 51
- priority 要比 MASTER 小
- unicast_src_ip 要设置正确,组播地址设置之后,要注释 vrrp_strict 选项
4)配置 HAProxy 检查
以上配置定义了 Keepalived 的 MASTER 节点和 BACKUP 节点,并设置对外提供服务的虚拟 IP 为 192.168.19.100。此外最主要的是定义了通过 haproxy_check.sh
来对 HAProxy 进行监控,这个脚本需要我们自行创建,内容如下:
vim /etc/keepalived/haproxy_check.sh
#!/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
创建后为其赋予执行权限
chmod +x /etc/keepalived/haproxy_check.sh
这个脚本主要用于判断 HAProxy 服务是否正常,如果不正常且无法启动,此时就需要将本机 Keepalived 关闭,从而让虚拟 IP 漂移到备份节点。
5)配置并启动服务
配置 IP 转发,需要修改配置文件 /etc/sysctl.conf
,默认只有 root 可以修改,分别在 MASTER 和 BACKUP上修改。
# 切换用户
su -root
# 文件配置
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
# 生效
sysctl -p
node1 和 node2 上启动 KeepAlived 服务,命令如下:
systemctl start keepalived
设置开机自动启
systemctl enable keepalived
启动后此时 node1 为主节点,可以在 node1 上使用 ip a
命令查看到虚拟 IP 的情况:
漂移规则如下:
- 默认使用 MASTER 服务器(192.168.19.102),虚拟 IP 为
192.168.19.100
,此时 MASTER 服务器会有 2 个IP。 - 当 MASTER 出问题时,IP 会漂移到 BACKUP 服务器(192.168.19.103),此时 BACKUP 服务器会有 2 个IP。
- 当 MASTER 重新启动后,虚拟 IP 又会漂移回 MASTER 服务器。
6)验证故障转移
这里我们验证一下故障转移,因为按照我们上面的检测脚本,如果 HAProxy 已经停止且无法重启时 KeepAlived 服务就会停止,这里我们直接使用以下工具进行验证。
安装 tcpdump 包
yum -y install tcpdump
- 在 MASTER 服务器上执行
tcpdump -i ens32 vrrp -n
这表明 MASTER 在向 BACKUP 广播,MASTER 在线。此时虚拟 IP 是挂在 MASTER 上的,如果想退出, 按 Ctrl+C
。
- 如果 MASTER 停止 keepalived,虚拟 IP 会漂移到 BACKUP 服务器上
# 停止 MASTER 的 keepalived
systemctl stop keepalived
- 再次在 MASTER 服务器上查看 VRRP 服务
这表明 MASTER 收到 BACKUP 的广播,此时虚拟 IP 是挂在 BACKUP 服务器上。
- 使用
ip a
分别查看
- 再次重启 MASTER 服务器,会发现 VIP 又重新漂移回 MASTER 服务器
7)消息发送接收测试
- 正常情况:所有服务都运行
-
只保留一个节点,停掉其它两个节点
因为node1、node2上安装有
HAProxy
和Keepalived
,至少保留一个
8)配置日志
注意
:此配置为可选步骤
keepalived 默认将日志输出到系统日志/var/log/messages
中,因为系统日志很多,查询问题时相对麻烦。
我们可以将 keepalived 的日志单独拿出来,这需要修改日志输出路径。
- 修改 Keepalived 配置
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 -d -S 0"
把 KEEPALIVED_OPTIONS=”-D” 修改为 KEEPALIVED_OPTIONS=”-D -d -S 0”,其中 -S 指定 syslog 的 facility
- 修改
/etc/rsyslog.conf
,末尾添加
vim /etc/rsyslog.conf
local0.* /var/log/keepalived.log
- 重启日志记录服务
systemctl restart rsyslog
- 重启 keepalived
systemctl restart keepalived
此时,可以从 /var/log/keepalived.log
查看日志了。
参考自:
- https://blog.csdn.net/qq_28533563/article/details/107932737
- https://www.bilibili.com/video/BV1cb4y1o7zz