RabbitMQ高可用集群搭建
RabbitMQ + HAProxy 高可用镜像模式集群部署
- 为什么搭建 RabbitMQ 集群?
- RabbitMQ 集群模式有哪些?
- 如何搭建 RabbitMQ 集群?
- RabbitMQ 镜像模式的策略如何配置?
RabbitMQ高可用集群搭建
部署说明
下面将以一个示例说明多机部署一个高可用 RabbitMQ 集群的流程。
前提
在部署集群前,必须在将成为集群成员的每个节点上安装 RabbitMQ,并确保每个节点之间能相互访问。
RabbitMQ 集群模式
普通模式(默认的集群模式)
以两个节点 node1、node2 为例来进行说明。
对于 queue 来说,消息实体只存在于其中一个节点(node1 或 node2),node1 和 node2 两个节点仅有相同的元数据,即队列的结构。当消息进入 node1 节点的 queue 后,consumer 从 node2 节点消费时,RabbitMQ 会临时在 node1、node2 间进行消息传输,把 node1 中的消息实体取出并经过 node2 发送给 consumer。所以 consumer 应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理 queue。否则无论 consumer 连接 node1 或 node2,出口总在 node1,会产生瓶颈。
当 node1 节点故障后,node2 节点无法取到 node1 节点中还未消费的消息实体。如果做了消息持久化,那么得等 node1 节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
镜像模式
把需要的队列做成镜像队列,存在于多个节点,属于 RabbiMQ 的 HA 方案,在对业务可靠性要求较高的场合中比较适用。
该模式解决了普通模式中的问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。
要实现镜像模式,需要先搭建一个普通集群模式,在这个模式的基础上再配置策略以实现高可用。
集群节点类型
- 内存(ram)节点
- 磁盘(disk)节点
RAM 节点仅将内部数据库表存储在 RAM 中。这不包括消息,消息存储索引,队列索引和其他节点状态。
在大多数情况下,您希望所有节点都是磁盘节点。 RAM 节点是一种特殊情况,可用于提高 queue、exchange 或 binding 流失率较高的群集的性能。 RAM 节点不提供更高的消息速率。如有疑问,请仅使用磁盘节点。
由于 RAM 节点仅将内部数据库表存储在RAM中,因此它们必须在启动时从对等节点同步它们。这意味着一个群集必须至少包含一个磁盘节点。因此,不可能手动删除集群中最后剩余的磁盘节点。
在 RabbitMQ 集群中,当磁盘节点宕掉且集群中无其他可用的磁盘节点时,集群将无法写入新的队列元数据信息。
环境准备
系统系统:CentOS7 64位
三台服务器:192.168.0.231/232/233
服务器规划
服务器 用途 主机名 节点类型 192.168.0.231 RabbitMQ 集群节点 1 node231 磁盘节点 192.168.0.232 RabbitMQ 集群节点 2 node232 磁盘节点 192.168.0.233 RabbitMQ 集群节点 3 node233 磁盘节点
集群搭建
普通模式
配置 hosts
vim /etc/hosts
编辑三个节点的 hosts 文件,在文件末尾添加如下内容:
1 | 192.168.0.231 node231 |
配置 hostname
node231
vim /etc/hostname
编辑主机名如下:1
node231
vim /etc/sysconfig/network
编辑网络配置文件,添加如下内容:1
2NETWORKING=yes
HOSTNAME=node231重启 network
1
systemctl restart network
node232
vim /etc/hostname
编辑主机名如下:1
node232
vim /etc/sysconfig/network
编辑网络配置文件,添加如下内容:1
2NETWORKING=yes
HOSTNAME=node232重启 network
1
systemctl restart network
node233
vim /etc/hostname
编辑主机名如下:1
node233
vim /etc/sysconfig/network
编辑网络配置文件,添加如下内容:1
2NETWORKING=yes
HOSTNAME=node233重启 network
1
systemctl restart network
配置 erlang cookie
RabbitMQ 集群是基于 erlang 进行同步的,在 erlang 的集群中各节点同步需要一个相同的 cookie,所以必须保证各节点 cookie 一致,不然节点之间就无法通信。这个 cookie 默认存放在 /var/lib/rabbitmq/.erlang.cookie
中。
在任意一个节点中 copy .erlang.cookie
文件到其它所有节点,如在 node1 上进行 copy :
1 | [root@node231 ~]# scp /var/lib/rabbitmq/.erlang.cookie root@192.168.0.232:/var/lib/rabbitmq/ |
重启节点
如果后面执行 rabbitmqctl stop_app
失败,需要重启 node231、node232、node233 使配置生效。
启动 rabbitmq-server
分别启动 node231、node232、node233 的 rabbitmq-server:
1 | [root@node231 ~]# systemctl start rabbitmq-server |
将节点加入集群
将 node232、node233 节点加入 node231 节点集群中,在 node232、node233 中分别执行以下命令:
1 | rabbitmqctl stop_app |
默认 RabbitMQ 启动后是磁盘节点,在这个 cluster 下,node231、node232 和 node233 都是是磁盘节点。
如果要使 node232、node233 都是内存节点,加上
--ram
参数即可,如rabbitmqctl join_cluster --ram rabbit@node232
。如果想要更改节点类型,可以使用命令
rabbitmqctl change_cluster_node_type disc(ram)
,修改节点类型前需要先rabbitmqctl stop_app
。(Note: disk and disc are used interchangeably)
查看集群状态
任意节点执行:
1 | rabbitmqctl cluster_status |
创建管理用户
如果在主机名变更前就已经创建过用户的,仍需要重新重新创建,因为主机名的变更,之前创建的用户无法登录 web 管理系统。
以下操作在 node231 下执行:
创建 vhost(可选,默认使用 "/" vhost)
这里创建一个 vhost 用于测试:
1
[root@node231 ~]# rabbitmqctl add_vhost testvhost
创建用户
1
[root@node231 ~]# add_user admin password
设置用户角色
1
[root@node231 ~]# set_user_tags admin administrator
设置用户权限
1
[root@node231 ~]# set_permissions -p testvhost admin ".*" ".*" ".*"
启用 rabbitmq management
在 node231 上启用 rabbitmq management
1 | [root@node231 ~]# rabbitmq-plugins enable rabbitmq_management |
在浏览器中访问 http://192.168.0.231:15672,使用 "admin/password" 即可登录。
镜像模式
上面已经完成 RabbitMQ 默认集群模式,但并不保证队列的高可用性,尽管 Exchanges、Bindings 这些可以复制到集群里的任何一个节点,但是队列内容不会复制。所以集群中的节点宕机后将直接导致队列无法应用或消息丢失,要想队列在节点宕机或故障时也能正常应用,需要复制队列内容到集群中的每个节点,这就要使用镜像队列了。
镜像队列
默认情况下,RabbitMQ 集群中 queue 的内容位于单个节点(声明该 queue 的节点)上。这与 exchanges 和 bindings 相反,exchanges 和 bindings 始终可以被视为在所有节点上。可以选择使 queue 跨多个节点进行镜像。
每个镜像队列由一个 master 和一个或多个镜像(mirrors)组成。master 托管在一个通常称为主节点的节点上。每个队列都有其自己的主节点。给定队列的所有操作都首先应用于队列的主节点,然后传播到镜像节点。这涉及排队发布,向消费者传递消息,跟踪来自消费者的确认等。
队列镜像意味着节点的集群。发布到队列的消息将复制到所有镜像。无论消费者连接到哪个节点,最终都会被连接到主节点,镜像节点都会丢弃已在主节点上确认的消息。因此,队列镜像可提高可用性,但不会在节点之间分配负载(所有参与的节点均完成所有工作)。
如果承载队列主节点发生故障,则最早的镜像将在同步后提升为新的主节点。根据队列镜像参数,也可以升级不同步的镜像。
配置镜像策略
使用策略(policiy)配置镜像参数。 一个策略按名称(使用正则表达式模式)匹配一个或多个队列,并且包含一个定义(可选参数的映射),该定义被添加到匹配队列的全部属性中。
通过控制台添加策略
如果其他节点也启用了 rabbitmq_management
,此时其他节点的控制台,可以看到上面添加的这个策略,如图所示:
参数说明:
Virtual host:策略应用的 vhost。
Name:为策略名称,可以是任何东西,但建议使用不带空格的基于ASCII的名称。
Pattern:与一个或多个 queue(exchange) 名称匹配的正则表达式,可以使用任何正则表达式。只有一个
^
代表匹配所有,^test
为匹配名称为 "test" 的 exchanges 或者 queue。Apply to:Pattern 应用对象。
Priority:配置了多个策略时候的优先级,值越大,优先级越高。
(没有指定优先级的消息会以0优先级对待。对于超过队列所定最大优先级的消息,优先级以最大优先级对待)
Definition:一组键/值对(例如 JSON 文档),将被插入匹配 queues and exchanges 的可选参数映射中
ha-mode
:策略键,分为3种模式all
- 所有(所有的 queue)exctly
- 部分(需配置ha-params
参数,此参数为 int 类型。比如 3,众多集群中的随机 3 台机器)nodes
- 指定(需配置ha-params
参数,此参数为数组类型。比如 ["rabbit@node2", "rabbit@node3"] 这样指定为 node2 与 node3 这两台机器)
ha-sync-mode
:队列同步manual
:手动(默认模式)。新的队列镜像将不会收到现有的消息,它只会接收新的消息automatic
:自动同步。当一个新镜像加入时,队列会自动同步。队列同步是一个阻塞操作。
通过命令行添加策略
设置
1
rabbitmqctl set_policy [-p <vhost>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>
清除
1
rabbitmqctl clear_policy [-p <vhost>] <name>
查看
1
rabbitmqctl list_policies [-p <vhost>]
例如:
1 | rabbitmqctl set_policy -p testvhost testha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}' |
1 | rabbitmqctl list_policies -p testvhost |
1 | rabbitmqctl clear_policy -p testvhost testha |
测试策略是否生效
在控制台的队列页面上,镜像队列将展示策略名称和其他副本(镜像)数量。以下是一个名为 three_replicas 的队列的示例,该队列具有一个 master(主节点)和两个镜像节点。
添加队列:
查看队列:
HAProxy 负载均衡
HAProxy 是由 C 语言编写的免费的开源软件,它快速而高效,可为基于TCP和HTTP的应用程序提供高可用、高性能的负载平衡器和代理服务器。
环境准备
服务器 | 用途 | 系统 | 版本 |
---|---|---|---|
192.168.0.235 | 负载均衡服务器 | Ubuntu 20.04 | haproxy 2.0 |
安装
1 | sudo apt install haproxy |
配置
vim /etc/haproxy/haproxy.cfg
编辑 haproxy 配置文件,修改如下:
1 | global |
验证 HAProxy 配置
修改配置后,在启动 HAProxy 前,应先运行以下命令验证配置文件语法:
1 | haproxy -f /etc/haproxy/haproxy.cfg -c -V |
如果收到错误消,请务必先修复,然后再继续。
运行 HAProxy
1 | systemctl restart haproxy |
查看状态:
1 | systemctl status haproxy |
HAProxy Statistics
浏览器访问 http://192.168.0.235:8888/stats,输入配置中的用户名和密码登录:
References
https://www.rabbitmq.com/clustering.html
https://www.rabbitmq.com/ha.html