clustering
使用集群的原因
最开始我们介绍了如何安装及运行RabbitMQ服务,不过这些是单机版的,无法满足目前真实应用的要求。如果RabbitMQ服务器遇到内存崩溃、机器掉电或者主板故障等情况,该怎么办?单台 RabbitMQ服务器可以满足每秒1000条消息的吞吐量,那么如果应用需要RabbitMQ服务满足每秒 10万条消息的吞吐量呢?购买昂贵的服务器来增强单机RabbitMQ服务的性能显得捉襟见肘,搭建一个 RabbitMQ 集群才是解决实际问题的关键。
普通集群(副本集群)
默认情况下: RabbitMQ代理操作所需的所有数据/状态都将跨所有节点复制。这方面的一个例外是消息队列,默认情况下,消息队列位于一个节点上,尽管它们可以从所有节点看到和访问
核心解决问题: 当集群中某一时刻master节点宕机,可以对Quene中信息,进行备份
方式一
1.修改3台机器的主机名称
vim /etc/hostname
2.配置各个节点的hosts文件,让各个节点都能互相识别对方
vim /etc/hosts
10.211.55.74 node1
10.211.55.75 node2
10.211.55.76 node3
3.以确保各个节点的 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
4.启动 RabbitMQ 服务,顺带启动 Erlang 虚拟机和 RbbitMQ 应用服务(在三台节点上分别执行以
下命令)
rabbitmq-server -detached
5.在节点 2 执行
rabbitmqctl stop_app
#(rabbitmqctl stop 会将 Erlang 虚拟机关闭,rabbitmqctl stop_app 只关闭 RabbitMQ 服务)
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@node1
rabbitmqctl start_app(只启动应用服务)
6.在节点 3 执行
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@node2
rabbitmqctl start_app
7.集群状态
rabbitmqctl cluster_status
8.需要重新设置用户
创建账号
rabbitmqctl add_user admin 123
设置用户角色
rabbitmqctl set_user_tags admin administrator
设置用户权限
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
9.解除集群节点(node2 和 node3 机器分别执行)
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
rabbitmqctl cluster_status
rabbitmqctl forget_cluster_node rabbit@node2(node1 机器上执行)
方式二
1.克隆三台主机
这里为了方便,我已经在克隆的主机上安装过rabbitmq,所以克隆的三台主机都已安装好rabbitmq
# 0.集群规划
node1: 192.168.77.139 mq1 master 主节点
node2: 192.168.77.140 mq2 repl1 副本节点
node3: 192.168.77.131 mq3 repl2 副本节点
2.修改ip地址
3台均是如此操作,分别修改为对应的ip
# 查看网络配置文件
ifconfig
# 修改配置文件
vim /etc/sysconfig/network-scripts/ifcfg-ens33
# 修改ip如下:
IPADDR=192.168.77.139
# 重启网络
systemctl restart network
3.修改主机名和ip映射
vim /etc/hosts
添加:
192.168.77.139 mq1
192.168.77.140 mq2
192.168.77.131 mq3
三台都要如此操作
# node1:
vim /etc/hostname
加入: mq1
# node2:
vim /etc/hostname
加入: mq2
# node3:
vim /etc/hostname
加入: mq3
# 重启机器生效
reboot
4.同步cookie文件
因为rabbitmq是基于erlang语言开发的,集群开发要求cookie必须一致
# 查看cookie是否一致:
node1: cat /var/lib/rabbitmq/.erlang.cookie
node2: cat /var/lib/rabbitmq/.erlang.cookie
node3: cat /var/lib/rabbitmq/.erlang.cookie
# 如果不一致,在node1上执行:[同步cookie]
scp /var/lib/rabbitmq/.erlang.cookie root@mq2:/var/lib/rabbitmq/
scp /var/lib/rabbitmq/.erlang.cookie root@mq3:/var/lib/rabbitmq/
5.测试各节点rabbitmq是否搭建成功
三台机器分别执行如下命令:
# 启动插件管理
rabbitmq-plugins enable rabbitmq_management
# 启动rabbitmq
systemctl start rabbitmq-server
注意:关闭防火墙
# 分别访问
http://192.168.77.139:15672/
http://192.168.77.140:15672/
http://192.168.77.141:15672/
至此,rabbitmq各个节点环境搭建成功
6.后台启动rabbitmq所有节点
如果你有使用管理插件方式启动rabbitmq,一定要先关掉
systemctl stop rabbitmq-server
再以后台方式启动rabbitmq:
rabbitmq-server -detached
注意:这种方式启动没有使用插件管理,所以还不能访问web界面
7.备节点加入集群
# 在node2和node3执行加入集群命令:
1.关闭 rabbitmqctl stop_app
2.加入集群 rabbitmqctl join_cluster rabbit@mq1
3.启动服务 rabbitmqctl start_app
往哪个节点加,那个被加入的节点就是主节点
8.查看集群状态
任意节点执行:
rabbitmqctl cluster_status
# 如果出现如下显示,集群搭建成功:
Cluster status of node rabbit@mq3 ...
[{nodes,[{disc,[rabbit@mq1,rabbit@mq2,rabbit@mq3]}]},
{running_nodes,[rabbit@mq1,rabbit@mq2,rabbit@mq3]},
{cluster_name,<<"rabbit@mq1">>},
{partitions,[]},
{alarms,[{rabbit@mq1,[]},{rabbit@mq2,[]},{rabbit@mq3,[]}]}]
9.登录管理界面
访问任意一台主机:
http://192.168.77.139:15672
10.测试
在node1上,创建队列,
查看node2和node3节点,
可以发现:主节点上创建队列,备节点node2和node3也可以看到相应队列
给主节点node1发送消息,查看node2和node3,
从node2或者node3上消费消息,
可以发现:可以消费消息,它最终也是从主节点node1上获取消息,它本身不提供消息
关闭node1节点,执行如下命令,查看node2和node3,
可以发现:主节点宕掉后,备节点可以看见队列,但不能提供服务,也即不能代替主节点做故障转移!
镜像集群
使用镜像的原因
如果RabbitMQ集群中只有一个 Broker 节点,那么该节点的失效将导致整体服务的临时性不可用,并且也可能会导致消息的丢失。可以将所有消息都设置为持久化,并且对应队列的durable属性也设置为true,但是这样仍然无法避免由于缓存导致的问题:因为消息在发送之后和被写入磁盘井执行刷盘动作之间存在一个短暂却会产生问题的时间窗。通过 publisherconfirm 机制能够确保客户端知道哪些消息己经存入磁盘,尽管如此,一般不希望遇到因单点故障导致的服务不可用。
引入镜像队列(Mirror Queue)的机制,可以将队列镜像到集群中的其他Broker节点之上,如果集群中的一个节点失效了,队列能自动地切换到镜像中的另一个节点上以保证服务的可用性。
镜像队列机制就是将队列在三个节点之间设置主从关系,消息会在三个节点之间进行自动同步,且如果其中一个节点不可用,并不会导致消息丢失或服务不可用的情况,提升MQ集群的整体高可用性。
注意:实际生产中使用还要配合LVS和负载均衡使用
注意: 镜像集群是在普通集群的基础上添加策略形成的,所以以下操作是在前面搭建好的普通集群上进行的
策略说明:
# 命令格式
rabbitmqctl set_policy [-p <vhost>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>
# 参数说明
-p Vhost: 可选参数,针对指定vhost下的queue进行设置
Name: policy的名称
Pattern: queue的匹配模式(正则表达式)
Definition:镜像定义,包括三个部分ha-mode, ha-params, ha-sync-mode
ha-mode:指明镜像队列的模式,有效值为 all/exactly/nodes
all:表示在集群中所有的节点上进行镜像
exactly:表示在指定个数的节点上进行镜像,节点的个数由ha-params指定
nodes:表示在指定的节点上进行镜像,节点名称通过ha-params指定
ha-params:ha-mode模式需要用到的参数
ha-sync-mode:进行队列中消息的同步方式,有效值为automatic和manual
priority:可选参数,policy的优先级
1.启动三台集群节点
2.查看当前策略
rabbitmqctl list_policies
3.随便找一个节点添加 policy
添加策略
说明: 策略正则表达式为 “^” 表示所有匹配所有队列名称 ^hello:匹配hello开头队列
这里我的队列hello与/ems虚拟主机进行了一个绑定,所以我在设置策略时,就针对该虚拟主机下的队列进行设置
rabbitmqctl set_policy ha-all -p '/ems' '^hello' '{"ha-mode":"all","ha-sync-mode":"automatic"}'
4.查看界面
5.测试
在 node1 上创建一个队列发送一条消息,队列存在镜像队列,向主节点发送消息,其他节点也可以进行同步。
停掉 node1 之后发现 node2 成为镜像队列 ,现关闭主节点,查看另外两个节点node2和node3
可以发现:备节点node2代替成为主节点。
消费节点node2或者node3的消息,可以正常消费消息
再次启动节点node1,发现主节点还是node2节点,node1成为备用节点
就算整个集群只剩下一台机器了 依然能消费队列里面的消息,说明队列里面的消息被镜像队列传递到相应机器里面了。
Haproxy+Keepalive 实现高可用负载均衡
整体架构图
Haproxy 实现负载均衡
HAProxy提供高可用性、负载均衡及基于TCP、HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案,包括 Twitter,Reddit,StackOverflow,GitHub在内的多家知名互联网公司在使用。HAProxy 实现了一种事件驱动、单一进程模型,此模型支持非常大的井发连接数。
扩展 nginx,lvs,haproxy 之间的区别: http://www.ha97.com/5646.html
搭建步骤
1.下载 haproxy(在 node1 和 node2)
yum -y install haproxy
2.修改 node1 和 node2 的 haproxy.cfg
vim /etc/haproxy/haproxy.cfg
需要修改红色IP为当前机器 IP
3.在两台节点启动 haproxy
haproxy -f /etc/haproxy/haproxy.cfg
ps -ef | grep haproxy
4.访问地址
http://10.211.55.71:8888/stats
Keepalived 实现双机(主备)热备
试想如果前面配置的HAProxy主机突然宕机或者网卡失效,那么虽然RbbitMQ集群没有任何故障但是对于外界的客户端来说所有的连接都会被断开结果将是灾难性的为了确保负载均衡服务的可靠性同样显得十分重要,这里就要引入Keepalived它能够通过自身健康检查、资源接管功能做高可用(双机热备),实现故障转移。
搭建步骤
1.下载 keepalived
yum -y install keepalived
2.节点 node1 配置文件
vim /etc/keepalived/keepalived.conf
把资料里面的 keepalived.conf 修改之后替换
3.节点 node2 配置文件
需要修改 global_defs 的 router_id,如:nodeB
其次要修改 vrrp_instance_VI 中 state 为"BACKUP";
最后要将 priority 设置为小于 100 的值
4.添加 haproxy_chk.sh
(为了防止HAProxy服务挂掉之后Keepalived还在正常工作而没有切换到Backup上,所以这里需要编写一个脚本来检测HAProxy服务的状态,当HAProxy服务挂掉之后该脚本会自动重启HAProxy的服务,如果不成功则关闭Keepalived服务,这样便可以切换到Backup继续工作)
#(可以直接上传文件)
vim /etc/keepalived/haproxy_chk.sh
#修改权限
chmod 777 /etc/keepalived/haproxy_chk.sh
5.启动 keepalive 命令(node1 和 node2 启动)
systemctl start keepalived
6.观察 Keepalived 的日志
tail -f /var/log/messages -n 200
7.观察最新添加的 vip
ip add show
8.node1 模拟 keepalived 关闭状态
systemctl stop keepalived