RabbitMQ的分布式
首先我们要了解RabbitMQ的集群架构模式,比如主备、shovels、镜像集群队列、异步多集群
然后从0开始构建一个异步的镜像队列集群,然后整合HAProxy和keepalive,实现高可用、高可靠。
然后我们来讲解下配置文件中的一些关键配置的含义和推荐配置。
j接下来我们来看看运维工作,结合场景来理解下恢复和失败转移的5种方案。
1.RabbitMQ的分布式简介
https://www.rabbitmq.com/distributed.html#overview
有三种方法可以实现RMQ的分布式:集群、联邦、Shovel插件。请注意,这三种方法并不是相互排斥的,可以组合使用:集群可以通过Federation或Shovel连接在一起,以获得更高的灵活性。
{1}集群:
集群节点可以帮助提高队列内容的可用性和数据安全性,并维持更多的并发客户机连接。集群、仲裁队列和经典镜像队列指南提供了有关这些主题的更多细节。
虚拟主机,交换机,用户和权限会在所有节点间共享,队列可以位于单个节点上,或者同步到其他节点以实现HA,仲裁队列是一种关注安全的多副本队列。经典队列可以选择是否做镜像。
连接到集群中任何节点的客户机可以使用集群中的所有非独占队列,即使它们不在该节点上。
{2}联邦:
联邦机制允许一个broker上的交换机或者队列接收其他broker上交换机或者队列发布的消息(这个broker可以是单独的机器或者其他集群上的)。通过AMQP(SSL可选),如果2个交换机或者队列通过联邦机制连接,比如设置相应的用户和权限。
联邦exchange是用单向的点对点链接连接的。默认情况下,消息将只在联合链接上转发一次,但可以增加转发次数,以适应更复杂的路由拓扑。有些消息可能不会通过该链接转发;如果消息到达联邦exchange后没有被路由到队列,那么它一开始就不会被转发。
联邦队列会简单的通过单向的点对点连接,消息会跟随消费者在联邦队列之间移动任意次。
通常,你可以使用联邦机制在internet 上通过广播和工作队列来连接broker。
{3}Shovels:
使用Shovel插件连接broker在概念上与使用Federation机制连接broker相似。然而,插件工作在一个较低的级别。
federation的目的是为交换和队列提供严格的(opinionated )分布,而shovel只是简单地从一个broker上的queue中获取消息,并将其转发给另一个broker上的exchange。
通常,如果你需要比联邦机制更多的控制,你会使用shovel去连接brokers。
动态Shovel用于在单个代理上以特别的方式移动消息。
Federation and/or Shovel | Clustering |
Brokers在逻辑上是隔离的,会有不同的owner | 逻辑上是单个Broker节点 |
broker可以运行不同版本的RabbitMQ和Erlang(在某些方面是不兼容的)。 | 所有节点必须运行在匹配的RabbitMQ和Erlang |
各个Broker节点可以通过广域网互连,当然要先授予适当的用户和权限 | Broker必须通过合理可靠可信任的局域网连接。通过Erlang内部节点传递消息,但节点间要有相同的Erlang cookie |
Broker以任何拓扑连接。链接可以是单向的,也可以是双向的。 | 节点之间的链接都是双向的 |
从CAP理论中选择可用性和分区耐受性,即AP | 从CAP理论中选择一致性和可用性,CA |
代理中的一些交换可能是基于Federation的,而另一些可能是本地的。 | 集群中所有Broker节点中的交换机都是一样的,要么全有要么全无 |
客户端能看到它所连接的Broker节点上的队列 | 客户端连接到及群众任何节点的客户机可以在所有节点的非独占队列。 |
2.分布式架构模式
{1}主备模式
主备与主从的区别
- 主备和主从的概念是有区别的,主备是主节点可以提供读写的,备用节点是不提供任何读写的,只是一个备用的服务。
- 主要的目的就是在主节点产生故障或者宕机的时候它能够实现一个自动切换,由原来的主节点切换到我们的备用节点,由备用节点继续提供读写服务,这时候备用节点就是充当主节点的角色了。而原来的节点恢复后又会加入到集群中,变成了备用节点。
- 主从是主服节点可以提供读写,但从节点是只读的。主从更多的是实现读写分离和数据备份的效果。
主备模式的特点
- 主备模式,也称之为Warren模式,即主节点如果挂了,切换到从节点继续提供服务,和activemq利用zookeeper做主/备是一样的效果。
- 主备未必是两个节点,可以一主多备。
- 主备模式:实现RabbitMQ的高可用集群,一般在并发和数据量不高的情况下,这种模型非常的好用且简单。
主备集群架构
如图为主备模式的简单架构模型,主要是利用HaProxy
去做的主备切换,当主节点挂掉时,HaProxy
会自动进行切换,把备份节点升级为主节点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pbcZE15G-1617066262538)(RabbitMQ1.assets/14795543-cb22a5c135be9073.png)]
HaProxy配置
HAProxy 是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,需要进行配置
{2}远程模式(Shovel)
远程模式:远距离通信和复制,可以实现双活的一种模式,简称Shovel模式。我们可以把消息进行不同数据中心的复制工作,我们可以跨地域的让多个mq集群互联。
架构模型
Shovel架构模型:绿色部分就代表了两个不同地域的MQ节点,假设用户在A地方下一个订单,然后订单投递到了MQ,第一个地方的MQ节点为了避免压力过大、负载过高可以设置一个阈值,如果负载过高将订单信息转到另一个地方的MQ,分摊服务压力。同时也可以进行两个或多个中心的数据同步。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vNwZROgI-1617066262540)(RabbitMQ1.assets/14795543-51e02588c0c7973d.jpg)]
好处:在使用了shovel插件后,模型变成了近端同步确认,远端异步确认的方式,大大提高了订单确认速度,并且还能保证可靠性
Shovel集群的拓扑图如下所示 ,一个订单进来之后,里面有两个队列,如果正常队列压力过大,会将订单路由到右边的backup队列,这个backup队列和另一个地域的MQ(某个交换机)产生了Shovel联系,就会把数据复制到远端MQ中心,在远端会有相应的队列进行消费
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rwrIoYrk-1617066262542)(RabbitMQ1.assets/14795543-460a5db89f698889.jpg)]
远程模式的使用
- Shovel集群的配置,首先启动rabbitmq插件,命令如下:
rabbitmq-plugins enable amqp_client
rabbitmq-plugins enable rabbitmq_shovel
- 创建rabbitmq.config文件:
touch /etc/rabbitmq/rabbitmq.config
- 在config文件中添加相关的配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e5CTYRns-1617066262543)(file://E:/teach/0804RabbitMQ/%E8%A1%A5%E5%85%85%EF%BC%9A10.RabbitMQ/10.RabbitMQ1.assets/Snipaste_2020-06-01_16-04-25-1615512791511.png?lastModify=1615512787)]
主要是来源和目的地的设置,2个地址设置好后还要设置公共的routing key,如果A中心的压力过大,想要转移到B中心,这个routing key如何去指定。下面是ACK的模式, - 最后我们需要源服务器和目的地服务器都使用相同的配置文件(rabbitmq.config)
事实上这个配置会相对复杂一些,实现双活已经有更好的方式,所以远程模式了解即可。
{3}镜像模式
- 镜像模式:集群模式非常经典的就是Mirror镜像模式,保证100%数据不丢失,在实际工作中也是用的最多的。
- 并且实现集群非常的简单,一般互联网大厂都会构建这种镜像集群模式。
- Mirror镜像队列,目的是为了保证rabbitmq数据的高可靠性解决方案,主要就是实现数据的同步,一般来讲是2-3个节点实现数据同步(对于100%数据可靠性解决方案一般是3节点)
集群架构
红色的虚线框就是镜像队列的集群
黄色的就是应用服务器,里面红色的部分包含了RabbitMQ节点,节点里面有个Mirror queue
,这三个镜像队列数据是要同步的。
前端用keepavlived做负载均衡,因为应用的连接可能连接3个节点的任意一个,那为什么要用到keepavlived呢,因为我们要做多个HA-proxy,比如一个HA-proxy挂了,我们虚拟的对外ip会飘移到另外的一个蓝色节点继续提供服务。
外部发送一条消息,落到一台服务器上,这台服务器将数据进行同步,同步到另外两个节点上。
利用HA-proxy
做负载均衡,然后KeepAlived
做多个HA-proxy的高可用切换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g8v7xzrm-1617066262544)(RabbitMQ1.assets/14795543-853fa98d8d0282ff.jpg)]
{4}多活模式(Federation)
- 多活模式:这种模式也是实现异地数据复制的主流模式,因为Shovel模式配置比较复杂,尤其是一些版本的限制,会导致Shovel模式的构建更加的繁琐。所以一般来说实现异地集群都是使用这种双活或者多活模型来实现的。
- 这种模型需要依赖rabbitmq的
federation
插件,可以实现持续的可靠的AMQP数据通信,多活模式在实际配置与应用上非常的简单。 - 提供了更可靠的完备的数据保障,即使一个集群挂掉,也还有另外一个集群。
- RabbitMQ部署架构采用双中心模式(多中心) , 这就意味着我有多套RabbitMQ集群,那么在两套(或多套)数据中心中各部署一套RabbitMQ集群,各中心的RabbitMQ服务除了需要为业务提供正常的消息服务外,中心之间还需要实现部分队列消息共享,也就是现在多中心的数据同步。
- 多活模式还能避免整个集群挂掉导致的数据丢失和服务宕机
多活集群架构
上层就是应用层,然后经过LBS负载均衡,两套RabbitMQ集群,可能是两套镜像队列,两套集群通过federation插件进行数据的复制和流转。
federation插件不是建立在集群上的,而是建立到单个节点上,比如左边node3可以和右边任意一台建立这种多活机制,然后,自己这边的集群如果是采用镜像队列那么也会在自己集群内部去进行同步,所以这种性能也是非常好的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8VkIQpp-1617066262545)(RabbitMQ1.assets/14795543-dcb47808c4abb0e1.jpg)]
Federation插件
- Federation插件是一个不需要构建Cluster,而在Brokers之间传输消息的高性能插件,Federation 插件可以在Brokers或者Cluster之间传输消息,连接的双方可以使用不同的users和virtual hosts,双方也可以使用版本不同的RabbitMQ和Erlang。Federation插件非常灵活好用。
- Federation 插件使用AMQP协议通讯,可以接受不连续的传输
- Federation Exchanges,可以看成Downstream从Upstream主动拉取消息,但并不是拉取所有消息,必须是在Downstream上已经明确定义Bindings关系的Exchange,也就是有实际的物理Queue来接收消息,才会从Upstream拉取消息到Downstream。使用AMQP协议实施代理间通信,Downstream会将绑定关系组合在一起,绑定/解除绑定命令将发送到Upstream交换机。因此,FederationExchange只接收具有订阅的消息。
流转过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f5DTu74I-1617066262546)(RabbitMQ1.assets/14795543-f38fbe2d746d9fb7.jpg)]
- upstream是上游,上下游之间要建立一个link
- 如图所示上游服务和下游服务,建立一个Link连接,可以认为就是federation,X代表Exchange
- 上游过来的数据,可以通过Exchange,直接转到下游,下游Exchange去接收数据,然后路由到具体的队列进行消费。
- 上游过来的数据不是说所有的数据都会流转到下游的,而是说建立对应关系,下游需要有具体的队列进行存储。
- 上游也可以自己去监听,同一个数据可以发到两个集群中,都可以用队列去接收存储然后消费。
3.镜像队列 + HA-proxy + keepalived的搭建
一共5台节点,3台搭建集群,2台作为HA-proxy和keepalived。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PMWgWgCM-1617066262547)(RabbitMQ1.assets/image-20210312100746202.png)]
{1}镜像队列集群搭建
- 3个节点都安装RMQ
- 3个节点都停止RMQ服务
rabbitmqctl stop - 文件同步
PS:选择76、77、78任意一个节点为Master(这里选择76为Master),也就是说我们需要把76的Cookie文件同步到77、78节点上去,进入/var/lib/rabbitmq目录下,把/var/lib/rabbitmq/.erlang.cookie文件的权限修改为777,原来是400;然后把.erlang.cookie文件copy到各个节点下;最后把所有cookie文件权限还原为400即可。
- 组成集群操作
PS:接下来我们就可以使用集群命令,配置76、77、78为集群模式,3个节点(76、77、78)执行启动命令,后续启动集群使用此命令即可。
- slave加入集群操作(重新加入集群也是如此,以最开始的主节点为加入节点)
- 修改RabbitMQ集群名称
PS:修改集群名称(默认为第一个node名称):
任意节点执行都可以
- 查看集群状态
PS:最后在集群的任意一个节点执行命令:查看集群状态
rabbitmqctl cluster_status - 管控台界面
PS: 访问任意一个管控台节点,显示的都是集群的信息:http://192.168.11.71:15672 如图所示 - 配置镜像队列
PS:设置镜像队列策略(在任意一个节点上执行)
PS:将所有队列设置为镜像队列,即队列和队列的数据会被复制到各个节点,各个节点状态一致,
此时RabbitMQ高可用集群就已经搭建好了,我们可以重启服务,查看其队列是否在从节点同步。
此时查看UI界面,每个队列都会同步到所有节点
listener points变为3
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zg9Xac90-1617066262547)(RabbitMQ1.assets/image-20210312103020601.png)]
{2}整合HAproxy
HaProxy是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。
HaProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HaProxy运行在时下的硬件上,完全可以支持数以万计的并发连接,并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上
HA-proxy性能最大化
- 单进程、事件驱动模型显著降低了上下文切换的开销及内存占用
- 在任何可用的情况下,单缓冲机制能以不复制任何数据的方式完成读写操作,会节约大量的cpu时钟周期及内存宽带
- 借助Lunix上的splice()系统调用,HaProxy可以实现零复制转发,还可以实现零复制启动
- 内存分配器在固定大小的内存池中可实现即时内存分配,能显著减少创建一个会话的时长
- 树形存储:侧重于使用弹性二叉树,实现了以O(log(N))的低开销来保持计时器命令、保持运行队列命令及管理轮询及最少连接队列
Haproxy安装
PS:79、80节点同时安装Haproxy,下面步骤统一
Haproxy配置
PS:haproxy 配置文件haproxy.cfg详解
启动haproxy
访问haproxy
PS:访问如下地址可以对rmq节点进行监控:http://192.168.1.27:8100/rabbitmq-stats
此时代理的是3台RabbitMQ节点,绿色表示正常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YGs9rRFj-1617066262548)(RabbitMQ1.assets/image-20210312104907028.png)]
关闭haproxy
{3}整合KeepAlived
简介
Keepalived,它是一个高性能的服务器高可用或热备解决方案,Keepalived主要来防止服务器单点故障的发生问题,可以通过其与Nginx、Haproxy等反向代理的负载均衡服务器配合实现web服务端的高可用。Keepalived以VRRP协议为实现基础,用VRRP协议来实现高可用性(HA).VRRP(Virtual Router Redundancy Protocol)协议是用于实现路由器冗余的协议,VRRP协议将两台或多台路由器设备虚拟成一个设备,对外提供虚拟路由器IP(一个或多个)。
KeepAlived软件主要是通过VRRP协议实现高可用功能。VRRP是Virtual Router RedundancyProtocol(虚拟路由器冗余协议)的缩写,VRRP出现的目的就是为了解决静态路由单点故障的问题,他能够保证当个别节点宕机时,整个网络可以不间断地运行。KeepAlived以方便具有配置管理LVS的功能,同时还具有对LVS下面节点进行健康检查的功能,另一方面也可以实现系统网络服务的高可用功能
keepalived用来实现集群的高可用,对外提供一个统一vip,然后根据策略将请求转发到某个节点处理。
haproxy和keepalived必须在一台机器里一起部署,不能分开。本质就是ha对rabbitmq的每个broker做负载均衡,而keep对两台ha服务器做高可用,那么既然keep是针对ha,所以必须要把ha和keep放到一起部署才有意义。
功能
- 管理LVS负载均衡软件
- 实现LVS集群节点的健康检查
- 作为系统网络服务的高可用性(failover)
高可用原理:
通过VRRP协议实现,在KeepAlived服务正常工作时,主节点会不断地向备节点发送(多播方式)心跳小新,用以高速备节点自己还活着,当主节点故障时,就无法发送心跳消息,备节点也因此无法继续检测到来自主节点的心跳,于是调用自身的截关程序,接管主节点的IP资源及服务。当主节点恢复时,备节点又会释放主节点故障时自身接管的IP资源及服务,恢复到原来的备用角色
安装
配置
通过一个脚本不断去检查节点是否健康,如果不健康,就去调用haproxy的命令去切换
- 主节点配置
主从不同的地方就是router_id、state、mcast_src_ip
- 从节点
启动keepalived
PS:当我们启动俩个haproxy节点以后,我们可以启动keepalived服务程序:
高可用测试
在keepalived和haproxy都正常运行的情况下,A节点是主节点。
A节点执行ip a命令,会有2个inet的ip,B节点只有一个,然后把A节点的keepalived stop,之后A节点只会有一个,而B节点有2个,这就是高可用故障转移。
此时A节点的keepalived 重新start,会发现vip又回到了A节点。这个可以配置,是否优先使用主节点做vip。
4.集群配置
创建如下配置文件位于:/etc/rabbitmq目录下(如果是yum方式安装,会自动创建,如果是绿色安装,这个目录需要自己创建)
环境变量配置文件:rabbitmq-env.conf
配置信息配置文件:rabbitmq.config(可以不创建和配置,修改)
rabbitmq-env.conf配置文件:
更详细的配置参见: http://www.rabbitmq.com/configure.html#configuration-file
rabbitmq.config
配置文件信息修改:
/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.4/ebin/rabbit.app和rabbitmq.config配置文件配置任意一个即可,我们进行配置如下:
更详细的配置参见:http://www.rabbitmq.com/configure.html
5.集群恢复和故障转移的解决方案
集群肯定会出问题,比如某个节点挂了,机房断电,一个节点服务启动不了,磁盘坏了。
遇到这些情况该怎么恢复和故障转移呢?
前提:A和B组成一个镜像队列,B是master
- 场景1:A先停,B后停
方案1:B是Master,只要先启动B在启动A即可。或者启动A,在30秒之内启动B即可恢复镜像队列 - 场景2:A、B同时停机
方案2:可能机房掉电等原因造成,只需在30秒之内连续启动A和B即可恢复镜像 - 场景3:A先停,B后停,且A无法恢复
方案3:该场景是场景1加强版,因为B是Master,所以等B起来后,在B节点上调用控制台命令rabbitmqctl forget_cluster_node A
解除与A的Cluster关系,再将新的Salve节点加入B即可重新恢复镜像队列 - 场景4:A先停,B后停,且B无法恢复
方案4:该场景是场景3加强版,比较难处理,因为Master节点无法恢复。B是主节点,B无法启动时,A也无法启动,也就无法在A节点上调用rabbitmqctl forget_cluster_node B
。
早在3.1.x时代之前貌似都没什么好的解决方法,但是现在已经有解决方法了,在3.4.2 版本亲测有效。
可以使用新的命令rabbitmqctl forget_cluster_node --offline B
。
这就意味着允许rabbitmqctl在理想节点上执行该命令,迫使RabbitMQ在未启动Slave节点中选择一个节点作为Master。当在A节点执行rabbitmqctl forget_cluster_node --offline B时,RabbitMQ会mock一个节点代表A,执行forget_cluster_node命令将B剔除cluster,然后A就可以正常启动了,最后将新的Slave节点加入A即可重新恢复镜像队列。 - 场景5:A先停、B后停,且A、B均无法恢复,但是能得到A或B的磁盘文件
方案5:该场景是场景4的加强版,更加难处理。只能通过恢复数据的方式去尝试恢复,将A或B的数据文件默认在$RABBIT_HOME/var/lib目录中,把它拷贝到新节点C的对应目录下,再将新节点C的hostname改成A或B的hostname,如果拷过来的是A节点(Slave)的磁盘文件,则按照场景4处理即可,如果拷过来的是B节点(Master)的磁盘文件,则按照场景3处理,最后将新的Slave加入到新节点完成恢复 - 场景6:A先停、B后停,且A、B均无法恢复,且得不到A或B的磁盘文件
方案6:无解
``