RabbitMQ Cluster
RabbitMQ 的单节点安装
https://www.jianshu.com/p/fed2efe62147
RabbitMQ Server 高可用集群相关概念
设计集群的目的
- 允许消费者和生产者在 RabbitMQ 节点崩溃的情况下继续运行。
- 通过增加更多的节点来扩展消息通信的吞吐量。
集群配置方式
-
cluster:不支持跨网段,用于同一个网段内的局域网;可以随意的动态增加或者减少;节点之间需要运行相同版本的 RabbitMQ 和 Erlang。
-
federation:应用于广域网,允许单台服务器上的交换机或队列接收发布到另一台服务器上交换机或队列的消息,可以是单独机器或集群。federation 队列类似于单向点对点连接,消息会在联盟队列之间转发任意次,直到被消费者接受。通常使用 federation 来连接 internet 上的中间服务器,用作订阅分发消息或工作队列。
-
shovel:连接方式与 federation 的连接方式类似,但它工作在更低层次。可以应用于广域网。
节点类型
- RAM node:内存节点将所有的队列、交换机、绑定、用户、权限和 vhost 的元数据定义存储在内存中,好处是可以使得像交换机和队列声明等操作更加的快速。
- Disk node:将元数据存储在磁盘中,单节点系统只允许磁盘类型的节点,防止重启 RabbitMQ 的时候,丢失系统的配置信息。
注意:RabbitMQ 要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必须要将该变更通知到至少一个磁盘节点。如果集群中唯一的一个磁盘节点崩溃的话,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到节点恢复。
解决方案:设置两个磁盘节点,至少有一个是可用的,可以保存元数据的更改。
Erlang Cookie
- Erlang Cookie 是保证不同节点可以相互通信的密钥,要保证集群中的不同节点相互通信必须共享相同的 Erlang Cookie。具体的目录存放在
/var/lib/rabbitmq/.erlang.cookie
。 - 默认
.erlang.cookie
文件是隐藏的,ls
命令不能查看,可以使用以下命令find / -name ".erlang.cookie"
说明:这就要从 rabbitmqctl 命令的工作原理说起,RabbitMQ 底层是通过 Erlang 架构来实现的,所以 rabbitmqctl 会启动 Erlang 节点,并基于 Erlang 节点来使用 Erlang 系统连接 RabbitMQ 节点,在连接过程中需要正确的 Erlang Cookie 和节点名称,Erlang 节点通过交换 Erlang Cookie 以获得认证。
镜像队列
RabbitMQ 的 Cluster 集群模式一般分为两种,普通模式和镜像模式。
- 普通模式:默认的集群模式,以两个节点(rabbit01、rabbit02)为例来进行说明。对于 Queue 来说,消息实体只存在于其中一个节点 rabbit01(或者 rabbit02),rabbit01 和 rabbit02 两个节点仅有相同的元数据,即队列的结构。当消息进入 rabbit01 节点的 Queue 后,consumer 从 rabbit02 节点消费时,RabbitMQ 会临时在 rabbit01、rabbit02 间进行消息传输,把 A 中的消息实体取出并经过 B 发送给 consumer。所以 consumer 应尽量连接每一个节点,从中取消息。==即对于同一个逻辑队列,要在多个节点建立物理 Queue。否则无论 consumer 连 rabbit01 或 rabbit02,出口总在 rabbit01,会产生瓶颈。==当 rabbit01 节点故障后,rabbit02 节点无法取到 rabbit01 节点中还未消费的消息实体。如果做了消息持久化,那么得等 rabbit01 节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
- 镜像模式:将需要消费的队列变为镜像队列,存在于多个节点,这样就可以实现 RabbitMQ 的 HA 高可用性。作用就是消息实体会主动在镜像节点之间实现同步,而不是像普通模式那样,在 consumer 消费数据时临时读取。缺点就是,集群内部的同步通讯会占用大量的网络带宽。
镜像队列实现了 RabbitMQ 的高可用性(HA),具体的实现策略如下所示:
ha-mode | ha-params | 功能 |
---|---|---|
all | 空 | 镜像队列将会在整个集群中复制。当一个新的节点加入后,也会在这 个节点上复制一份。 |
exactly | count | 镜像队列将会在集群上复制 count 份。如果集群数量少于 count 时候,队列会复制到所有节点上。如果大于 Count 集群,有一个节点 crash 后,新进入节点也不会做新的镜像。 |
nodes | node name | 镜像队列会在 node name 中复制。如果这个名称不是集群中的一个,这不会触发错误。如果在这个 node list 中没有一个节点在线,那么这个 queue 会被声明在 client 连接的节点。 |
实例:(更直观的方式是通过 Web 界面设置镜像队列,通过添加 policy 的方式)
queue_args("x-ha-policy":"all") //定义字典来设置额外的队列声明参数
channel.queue_declare(queue="hello-queue",argument=queue_args)
如果需要设定特定的节点(以rabbit@localhost
为例),再添加一个参数:
queue_args("x-ha-policy":"nodes",
"x-ha-policy-params":["rabbit@localhost"])
channel.queue_declare(queue="hello-queue",argument=queue_args)
可以通过命令行查看那个主节点进行了同步:
$ rabbitmqctl list_queues name slave_pids synchronised_slave_pids
搭建 RabbitMQ Server 高可用集群
默认.erlang.cookie
文件是隐藏的,ls
命令并不能查看,你也可以手动搜索下文件:
[root@node1 ~]# find / -name ".erlang.cookie"
/var/lib/rabbitmq/.erlang.cookie
[root@node1 ~]# cat /var/lib/rabbitmq/.erlang.cookie
LBOTELUJAMXDMIXNTZMB
将node1
服务器中的.erlang.cookie
文件,拷贝到node2
服务器上(拷贝前先关闭 rabbitmq 服务):
scp /var/lib/rabbitmq/.erlang.cookie root@node2:/var/lib/rabbitmq
# 需要 root 全权限密码
- 采坑:
.erlang.cookie
文件需要赋予权限才能操作
chmod 777 /var/lib/rabbitmq/.erlang.cookie # 两台机器都需要
# scp 之后收回权限
chmod 400 /var/lib/rabbitmq/.erlang.cookie
先停止运行节点,然后以后台方式启动 RabbitMQ Server(node1
和node2
分别执行):
[root@node1 ~]# rabbitmqctl stop
[root@node1 ~]# rabbitmq-server -detached
然后我们以node1
作为集群中心,在node2
上执行加入集群中心命令(节点类型为磁盘节点):
[root@node1 ~]# rabbitmqctl stop_app
[root@node1 ~]# rabbitmqctl reset
[root@node1 ~]# rabbitmqctl join_cluster rabbit@node1
//默认是磁盘节点,如果是内存节点的话,需要加--ram参数
[root@node1 ~]# rabbitmqctl start_app
查看集群的状态(包含node1
和node2
节点):
[root@node1 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@node1
[{nodes,[{disc,[rabbit@node1,rabbit@node2]}]},
{running_nodes,[rabbit@node2,rabbit@node1]},
{cluster_name,<<"rabbit@node1">>},
{partitions,[]},
{alarms,[{rabbit@node2,[]},{rabbit@node1,[]}]}]
我们可以从 RabbitMQ Web 管理界面,看到集群的信息:
rabbitmq_cluster_web.PNG