RabbitMq集群搭建
总阅读 次
RabbiMQ简介
RabbiMQ是用Erang开发的,集群非常方便,因为Erlang天生就是一门分布式语言,但其本身并不支持负载均衡。
RabbiMQ模式
RabbitMQ模式大概分为以下三种:
(1)单一模式。
(2)普通模式(默认的集群模式)。
(3) 镜像模式(把需要的队列做成镜像队列,存在于多个节点,属于RabbiMQ的HA方案,在对业务可靠性要求较高的场合中比较适用)。
要实现镜像模式,需要先搭建一个普通集群模式,在这个模式的基础上再配置镜像模式以实现高可用。
RabbiMQ特点
RabbitMQ的集群节点包括内存节点、磁盘节点。RabbitMQ支持消息的持久化
也就是数据写在磁盘上,最合适的方案就是既有内存节点,又有磁盘节点。
搭建环境:
IP地址 | 主机名 | 操作系统 | 防火墙和SELinux | 用途 |
---|---|---|---|---|
192.168.100.143 | mq01 | CentOS7.4(64位) | 关闭 | 磁盘节点 |
192.168.100.144 | mq02 | CentOS7.4(64位) | 关闭 | 内存节点 |
192.168.100.145 | mq03 | CentOS7.4(64位) | 关闭 | 内存节点 |
注意:RabbitMQ集群节点必须在同一网段里,如果是跨广域网,效果会变差。
搭建步骤
1. 配置hosts文件
更改三台MQ节点的计算机名分别为mq01、mq02 和mq03,然后修改hosts配置文件1
2
3
4
5
6
7vi /etc/hostname //其他两台相同,mq02,mq03
mq01
vi /etc/hosts
192.168.100.143 mq01 //注意不能带.注意-主机名称也要更改
192.168.100.144 mq02
192.168.100.145 mq03
注意:当主机名称不方便改动的情况,只修改hosts,同主机名就行
2.安装erlang和rabbitmq-server软件
在各个服务器上先安装好单机的rabbitmq,并能够成功启动,官方安装说明地址:https://www.rabbitmq.com/install-rpm.html#managing-service, 参考文件,选择合适的erlang和rabbitmq对应版本下载安装
由于服务器不可访问外网,所以本次通过官网下好rpm包,上传到服务器,再通过yum install安装
本次下载安装的版本为:
erlang-21.3.8.14-1.el7.x86_64.rpm 下载地址(https://bintray.com/rabbitmq-erlang/rpm/erlang)
rabbitmq-server-3.8.3-1.el7.noarch.rpm 下载地址(https://bintray.com/rabbitmq/rpm/rabbitmq-server)
根据系统CentOS的版本(6.x,7.x,8.x)选择合适的版本(el6,el7,el8)下载
分别使用如下命令安装1
2yum install -y erlang-21.3.8.14-1.el7.x86_64.rpm
yum install -y rabbitmq-server-3.8.3-1.el7.noarch.rpm
3.修改rabbitmq config配置
上一步安装完成,便可以通过systemctl start rabbitmq-server启动rabbitmq服务,通过启动日记,可以发现其未找到config文件,以及数据路径和日记路径都采用默认,这里我们做下调整优化,可以让rabbitmq使用更大上限的File descriptor,Disk space等
rabbitmq默认的加载配置文件在/etc/rabbitmq路径下,在此路径下新建rabbitmq-env.conf文件,来指明数据和日记存储的磁盘路径,内容如下:1
2MNESIA_BASE=/data/rabbitmq/data
LOG_BASE=/data/rabbitmq/log
通过df -h查看发现挂载的/data下有很大磁盘空间,遂放置于此。同时注意新建的/data/rabbitmq文件拥有设置为rabbitmq
使用命令:chown -R rabbitmq:rabbitmq /data/rabbitmq/
再新建rabbitmq.conf文件,内容如下:1
2
3
4
5
6
7
8
9
10
11listeners.tcp.default = 5672
channel_max = 655360
# partition config
cluster_partition_handling = autoheal
# DANGER ZONE!
# allowing remote connections for default user is highly discouraged
# as it dramatically decreases the security of the system. Delete the user
# instead and create a new one with generated secure credentials.
loopback_users = none
此处优化了channel_max的上限,cluster_partition_handling为网络分区策略设置为autoheal,参见文章最后,rabbitMq脑裂详解。配置loopback_users=none,使得默认账户guest/guest可以在非localhost的情况下登陆访问rabbitmq管理界面。
以上优化参数的配置,在官方文档中均有说明,同时提供example配置文件供参考
4. 安装管理插件
RabbitMQ提供了一个非常友好的图形化监控页面插件(rabbitmq_management),让我们可以一目了然看见Rabbit的状态或集群状态。1
2
3
4
5/usr/lib/rabbitmq/bin/rabbitmq-plugins list //查看插件安装情况
/usr/lib/rabbitmq/bin/rabbitmq-plugins enable rabbitmq_management //启用rabbitmq_management服务
systemctl restart rabbitmq-server
5. 调整最大可打开文件句柄限制
默认情况下,操作系统限制的rabbitmq的最大操作文件句柄256,往往会限制到rabiitmq的性能提升,这里需要调整到65536
打开rabbitmq-server文件,位于系统:/usr/lib/systemd/system/rabbitmq-server.service,可通过systemctl status rabbitmq-server查看到,修改如下:
1 | [Service] |
6.拷贝erlang.cookie
以上完成单一mq的服务部署,在三台服务器完成相同的部署操作,并能够成功启动,登陆访问管理界面。
Rabbitmq的集群是依附于erlang的集群来工作的,所以必须先构建起erlang的集群景象。Erlang的集群中各节点是经由过程一个magic cookie来实现的,这个cookie存放在/var/lib/rabbitmq/.erlang.cookie中,文件是400的权限。所以必须保证各节点cookie一致,不然节点之间就无法通信。
用scp的方式将mq01节点的.erlang.cookie的值复制到其他两个节点中。1
2
3scp /var/lib/rabbitmq/.erlang.cookie root@192.168.100.144:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie root@192.168.100.145:/var/lib/rabbitmq/.erlang.cookie
拷贝过程以及拷贝后注意文件权限问题。并重启三个服务应用。
7.将mq02、mq03作为内存节点加入mq01节点集群中
在mq02、mq03执行如下命令:1
2
3rabbitmqctl stop_app //停掉rabbit应用
rabbitmqctl join_cluster --ram rabbit@mq01 //加入到磁盘节点
rabbitmqctl start_app //启动rabbit应用
(1)默认rabbitmq启动后是磁盘节点,在这个cluster命令下,mq02和mq03是内存节点,mq01是磁盘节点。
(2)如果要使mq02、mq03都是磁盘节点,去掉–ram参数即可。
(3)如果想要更改节点类型,可以使用命令rabbitmqctl change_cluster_node_type disc(ram),前提是必须停掉rabbit应用
在RabbitMQ集群集群中,必须至少有一个磁盘节点,否则队列元数据无法写入到集群中,当磁盘节点宕掉时,集群将无法写入新的队列元数据信息。
8.查看集群状态
指令rabbitmqctl cluster_status或者登陆管理界面查看如图
9.RabbitMQ镜像集群配置
上面已经完成RabbitMQ默认集群模式,但并不保证队列的高可用性,尽管交换机、绑定这些可以复制到集群里的任何一个节点,但是队列内容不会复制。虽然该模式解决一项目组节点压力,但队列节点宕机直接导致该队列无法应用,只能等待重启,所以要想在队列节点宕机或故障也能正常应用,就要复制队列内容到集群里的每个节点,必须要创建镜像队列。
镜像队列是基于普通的集群模式的,然后再添加一些策略,所以你还是得先配置普通集群,然后才能设置镜像队列,我们就以上面的集群接着做。
设置的镜像队列可以通过开启的网页的管理端,也可以通过命令,分别如下。
1.网页管理端创建rabbitmq策略
在mq01节点的控制台上创建策略
(1)点击admin菜单–>右侧的Policies选项–>左侧最下下边的Add/update a policy。
(2)按照图中的内容根据自己的需求填写。
- Name:策略名称
- Pattern:匹配的规则,^a这里表示匹配a开头的队列,如果是匹配所有的队列,那就是^.
- Definition:使用ha-mode模式中的all,也就是同步所有匹配的队列。问号链接帮助文档。
(3)点击Add policy添加策略
此时分别登陆mq02、mq03两个节点的控制台,可以看到上面添加的这个策略
2.命令设置policy如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]
-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的优先级
例:rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all","ha-sync-mode":"automatic","ha-promote-on-shutdown":"always","ha-promote-on-failure":"always"}'
3.做破坏性测试
创建一个queue ab,像ab queue里发送一个message,自定义即可
1)将mq01节点的服务关闭,rabbitmqctl stop_app,再通过mq02和mq03查看消息记录是否还存在。从中可以看到ab队列已经从之前的+2显示成+1了,而且消息记录是存在的。
2)再将mq02节点的服务关闭,通过mq03查看消息记录是否还存在。从中可以看到ab队列和消息记录还是存在的,只是变成了一个节点了。
3)将mq01和mq02的服务再启动起来
从中可以看到ab队列后面+2变成了粉色,鼠标指上去显示镜像无法同步。如果这时候停掉mq03节点的服务,那么队列里面的消息将会丢失。
采取的解决办法是选择在mq02节点上执行同步命令。rabbitmqctl sync_queue ab //同步ab队列
同步完成后,+2又变成了蓝色。
这样,我们就测试了rabbitmq集群的破坏性测试,说明集群配置成功。
10.其他功能指令使用
新增账户:1
2
3
4
5
6
7rabbitmqctl add_user barry barry@123
rabbitmqctl list_users
rabbitmqctl set_user_tags barry administrator
rabbitmqctl list_users
rabbitmqctl set_permissions -p / barry '.*' '.*' '.*'
rabbitmqctl list_permissions barry
rabbitmqctl list_user_permissions barry
设置服务开机自启动1
systemctl enable rabbitmq-server //关闭disable
查看并删除队列1
2rabbitmqctl list_queues
rabbitmqctl delete_queue ***队列名
11.rabbitmq网络分区配置-脑裂详解
集群和网络分区
RabbitMQ集群并不能很好的“忍受”网络分区。如果你想将RabbitMQ集群建立在广域网上,记住那是行不通的,除非你使用federation或者shovel等插件。然而有时候会有一些意想不到的事情发生。
RabbitMQ会将queues, exchanges, bindings等信息存储在Erlang的分布式数据库——Mnesia中,许多围绕网络分区的一些细节都和这个Mnesia的行为有关。
检测网络分区
如果另一个节点在一分钟(或者一个net_ticktime时间)内不能连接上一个节点,那么Mnesia通常任务这个节点已经挂了。就算之后两个节点连通(译者注:应该是指网络上的可连通),但是这两个节点都认为对方已经挂了,Mnesia此时认定发送了网络分区的情况。这些会被记录在RabbitMQ的日志中。
当一个节点起来的时候,RabbitMQ会记录是否发生了网络分区,你可以通过rabbitmqctl cluster_status这个命令或者管理插件看到相关信息。正常情况下,通过rabbitmqctl cluster_status命令查看到的信息中partitions那一项是空的。
然而当网络分区发生时,partitions内容就变了,同时管理界面也会有提示。
网络分区期间
当一个集群发生网络分区时,这个集群会分成两部分(或者更多),它们各自为政,互相都认为对方分区内的节点已经挂了, 包括queues, bindings, exchanges这些信息的创建和销毁都处于自身分区内,与其他分区无关。如果原集群中配置了镜像队列,而这个镜像队列又牵涉到两个(或者多个)网络分区的节点时,每一个网络分区中都会出现一个master节点(译者注:如果rabbitmq版本较新,分区节点个数充足,也会出现新的slave节点。),对于各个网络分区,此队列都是互相独立的。当然也会有一些其他未知的、怪异的事情发生。
当网络(这里只网络连通性,network connectivity)恢复时,网络分区的状态还是会保持,除非你采取了一些措施去解决他。
挂起/恢复导致的分区
当我们涉及到“网络分区”时,当集群中的不同的节点发生交互失败中断(communication interrupted)等,但是又没有节点挂掉这种情况下,才是发生了分区。然而除了网络失败(network failures)原因,操作系统的挂起或者恢复也会导致集群内节点的网络分区。因为发生挂起的节点不会认为自身已经失败或者停止工作,但是集群内的其他节点会这么认为。
如果一个集群中的一个节点运行在一台笔记本上,然后你合上了笔记本,这样这个节点就挂起了。或者说一种更常见的现象,节点运行在某台虚拟机上,然后虚拟机的管理程序挂起了这个虚拟机节点,这样也可能发生挂起。
由于挂起/恢复导致的分区并不对称——挂起的节点将看不到其他节点是否消失,但是集群中剩余的节点可以观察到,这一点貌似暗示了pause_minority这种模式(下面会涉及到)。
从网络分区中恢复
未来从网络分区中恢复,首先需要挑选一个信任的分区,这个分区才有决定Mnesia内容的权限,发生在其他分区的改变将不被记录到Mnesia中而直接丢弃。
停止(stop)其他分区的节点,然后启动(start)这些节点,之后重新将这些节点加入到当前信任的分区之中。
最后,你应该重启(restart)信任的分区中所有的节点,以去除告警。
你也可以简单的关闭整个集群的节点,然后再启动每一个节点,当然,你要确保你启动的第一个节点在你所信任的分区之中。
自动处理分区
RabbitMQ提供了三种方法自动的解决网络分区:pause-minority mode, pause-if-all-down mode以及autoheal mode。(默认的是ignore模式)
在pause-minority mode下,顾名思义,当发生网络分区时,集群中的节点在观察到某些节点“丢失”时,会自动检测其自身是否处于少数派(小于或者等于集群中一半的节点数),RabbitMQ会自动关闭这些节点的运作。根据CAP原理来说,这里保障了P,即分区耐受性(partition tolerance)。这样确保了在发生网络分区的情况下,大多数节点(当然这些节点在同一个分区中)可以继续运行。“少数派”中的节点在分区发生时会关闭,当分区结束时又会启动。
在pause-if-all-down mode下,RabbitMQ在集群中的节点不能和list中的任何节点交互时才会关闭集群的节点({pause_if_all_down, [nodes], ignore | autoheal},list即[nodes]中的节点)。也就是说,只有在list中所有的节点失败时才会关闭集群的节点。这个模式和pause-minority mode有点相似,但是,这个模式允许管理员的任命而挑选信任的节点,而不是根据上下文关系。举个案例,一个集群,有四个节点,2个节点在A机架上,另2个节点在B机架上,此时A机架和B机架的连接丢失,那么根据pause-minority mode所有的节点都将被关闭。
在autoheal mode下,当认为发生网络分区时,RabbitMQ会自动决定一个获胜(winning)的分区,然后重启不在这个分区中的节点。
一个获胜的分区(a winning partition)是指客户端连接最多的一个分区。(如果产生一个平局,即有两个(或多个)分区的客户端连接数一样多,那么节点数最多的一个分区就是a winning partition. 如果此时节点数也一样多,将会以一个未知的方式挑选winning partition.)
你可以通过在RabbitMQ配置文件中设置cluster_partition_handling参数使下面任何一种模式生效:
pause_minority
{pause_if_all_down, [nodes], ignore | autoheal}
autoheal
我该挑选那种模式?
有一点必须要清楚,允许RabbitMQ能够自动的处理网络分区并不一定会有正面的成效,也有能会带来更多的问题。网络分区会导致RabbitMQ集群产生众多的问题,你需要对你所遇到的问题作出一定的选择。就像本文开篇所说的,如果你置RabbitMQ集群于一个不可靠的网络环境下,你需要使用federation或者shovel插件。
你可能选择如下的恢复模式:
ignore: 你的网络很可靠,所有的节点都在一个机架上,连接在同一个交换机上,这个交换机也连接在WAN上,你不需要冒险而关闭部分节点。(或者适合只有两个节点的集群。)
pause_minority: 你的网络相对没有那么的可靠。比如你在EC2上建立了三个节点的集群,假设其中一个节点宕了,在这种策略下,剩余的两个节点还可以继续工作,失败的节点可以在恢复之后重新加入集群
autoheal: 你的网络非常不可靠,你更关心服务的连续性而不是数据的完整性。适合有两个节点的集群。
有关pause-minority模式的更多信息
关闭的RabbitMQ节点所在主机上的Erlang虚拟机还是在正常运行,但是此节点并不会监听任何端口也不会执行其他任务。这些节点每秒会检测一次剩下的集群节点是否会再次出现,如果出现,就启动自己继续运行。
注意上面所说的“关闭的RabbitMQ节点”并不会在启动时就进入关闭状态,即使它们在“少数派(minority)”。这些“少数派”可能在“剩余的集群节点”没有启动好之前就启动了。
同样需要注意的是RabbitMQ也会关闭不是严格意义上的“大多数(majority)”——数量超过集群的一半。因此在一个集群只有两个节点的时候并不适合采用pause-minority模式,因为由于其中任何一个节点失败而发生网络分区时,两个节点都会被关闭。然而如果集群中的节点个数远大于两个时,pause_minority模式比ignore模式更加的可靠,特别是网络分区通常是由于单个节点掉出网络。
最后,需要注意的是pause_minority模式将不会防止由于集群节点被挂起而导致的分区。这是因为挂起的节点将永远不会看到集群的其余部分的消失,因此将没有触发器将其从集群中断开。