Linux 部署 RabbitMQ 集群

通常状况下,若是只是为了探究 RabbitMQ 或者验证业务工程的正确性那么在本地环境或者测试环境上使用其单实例部署就能够了,可是出于 MQ 中间件自己的可靠性、并发性、吞吐量和消息堆积能力等问题的考虑,在生产环境上通常都会考虑使用 RabbitMQ 的集群方案。node

本文档旨在介绍 RabbitMQ 集群的工做原理以及在 CentOS 7 系统上安装配置具有高可用性和具有必定负载能力的 RabbitMQ 集群。linux

RabbitMQ 集群工做原理介绍

RabbitMQ 这款消息队列中间件产品自己是基于 Erlang 编写,Erlang 语言天生具有分布式特性(经过同步 Erlang 集群各节点的 magic cookie 来实现)。所以,RabbitMQ 自然支持 Clustering。这使得 RabbitMQ 自己不须要像ActiveMQ、Kafka 那样经过 ZooKeeper 分别来实现 HA 方案和保存集群的元数据。集群是保证可靠性的一种方式,同时能够经过水平扩展以达到增长消息吞吐量能力的目的。git

RabbitMQ 集群有两种模式:github

  • 默认模式,以两个节点 mq1 和 mq2 为例来进行说明。对于 Queue 来讲,消息实体只存在于其中一个节点 mq1 或者 mq2 ,mq1 和 mq2 两个节点仅有相同的元数据,即队列的结构。当消息进入 mq1 节点的 Queue 后,consumer 从 mq2 节点消费时,RabbitMQ 会临时在 mq1 、mq2 间进行消息传输,把 A 中的消息实体取出并通过 B 发送给 consumer。因此 consumer 应尽可能链接每个节点,从中取消息。即对于同一个逻辑队列,要在多个节点创建物理 Queue。不然不管 consumer 连 mq1 或 mq2 ,出口总在 mq1,会产生瓶颈。当 mq1 节点故障后,mq2 节点没法取到 mq1 节点中还未消费的消息实体。若是作了消息持久化,那么得等 mq1 节点恢复,而后才可被消费;若是没有持久化的话,就会产生消息丢失的现象。
  • 镜像模式,把须要的队列作成镜像队列,存在与多个节点属于RabbitMQ 的 HA 方案。该模式解决了普通模式中的问题,其实质和普通模式不一样之处在于,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的反作用也很明显,除了下降系统性能外,若是镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通信大大消耗掉。因此在对可靠性要求较高的场合中适用。

RabbitMQ 集群部署

RabbitMQ 集群主机环境以下:bash

mq-node1(master)  10.200.100.231 master.yeaheo.com
mq-node2(node01)  10.200.100.231 node01.yeaheo.com
mq-node3(node02)  10.200.100.231 node02.yeaheo.com

各主机系统环境及 MQ 版本以下:cookie

$ cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)

$ uname -r
3.10.0-862.el7.x86_64

Erlang : 21.1
RabbitMQ: v3.7.9

修改各主机 hosts 文件以下:网络

....
10.200.100.231 master master.yeaheo.com
10.200.100.217 node01 node01.yeaheo.com
10.200.100.218 node02 node02.yeaheo.com
....

配置 RabbitMQ 集群首先须要在各个主机上安装并配置 Erlang 和 RabbitMQ ,Erlang安装过程能够参考: rabbitmq-erlang-installation.md RabbitMQ 具体过程能够参考:rabbitmq-single-installation.md并发

当 Erlang 和 RabbitMQ 安装完成后就能够配置 RabbitMQ 集群了。app

配置 RabbitMQ 集群

本次部署集群时都是将其余两个 RabbitMQ 加入到 master 主机现有集群中。socket

rabbitmq-server 启动时,会一块儿启动节点和应用,它预先设置 RabbitMQ 应用为 standalone 模式。要将一个节点加入到现有的集群中,你须要中止这个应用,并将节点设置为原始状态。若是使用 rabbitmqctl stop,应用和节点都将被关闭。因此使用 rabbitmqctl stop_app仅仅关闭应用

同步集群 cookie

RabbitMQ 利用 erlang 的分布式特性组建集群,erlang 集群经过 magic cookie 实现,此 cookie 保存在$home/.erlang.cookie,这里即:/var/lib/rabbitmq/.erlang.cookie,须要保证集群各节点的此 cookie 一致,能够选取一个节点的 cookie,采用 scp 同步到其余节点:

$ scp /var/lib/rabbitmq/.erlang.cookie root@node01:/var/lib/rabbitmq/.erlang.cookie
$ scp /var/lib/rabbitmq/.erlang.cookie root@node02:/var/lib/rabbitmq/.erlang.cookie

更换 cookie 后须要重启 RabbitMQ 服务:

$ systemctl stop rabbitmq-server.service
$ systemctl start rabbitmq-server.service

切换 RabbitMQ 启动方式

全部节点须要使用 -detached 参数启动服务:

# 须要在全部节点上执行
$ rabbitmqctl stop
$ rabbitmq-server -detached

组建 RabbitMQ 集群

由于将其余两个 RabbitMQ 加入到 master 主机现有集群中,因此只须要在 node01node02 上操做便可:

node01 主机(10.200.100.217)上操做:

node01$ rabbitmqctl stop_app
node01$ rabbitmqctl join_cluster rabbit@master         ####这里集群的名字必定不要写错了
node01$ rabbitmqctl start_app
集群名字通常能够在 master主机的日志文件中看到,须要注意的是这个集群名字须要和日志文件中保持一致,不然加入集群时会报错

node02 主机(10.200.100.218)上操做:

node02$ rabbitmqctl stop_app
node02$ rabbitmqctl join_cluster rabbit@master         ####这里集群的名字必定不要写错了
node02$ rabbitmqctl start_app

查看集群状态:

$ rabbitmqctl cluster_status
Cluster status of node rabbit@master ...
[{nodes,[{disc,[rabbit@master,rabbit@node01]},{ram,[rabbit@node02]}]},
 {running_nodes,[rabbit@node02,rabbit@node01,rabbit@master]},
 {cluster_name,<<"rabbit@master">>},
 {partitions,[]},
 {alarms,[{rabbit@node02,[]},{rabbit@node01,[]},{rabbit@master,[]}]}]

此时 node01node02 也会自动创建链接,集群配置完成。

若是要使用内存节点,则可使用 rabbitmqctl join_cluster --ram rabbit@master 加入集群。

RabbitMQ 节点分为内存节点和磁盘节点:

1)内存节点(RAM):内存节点将全部的队列、交换机、绑定、用户、权限和vhost的元数据定义存储在内存中
2)磁盘节点(Disk):将元数据存储在磁盘中,单节点系统只容许磁盘类型的节点,防止重启RabbitMQ的时候,丢失系统的配置信息。

若是须要切换节点类型,能够参考以下命令:

#若是节点已经是"disk"节点,能够修改成内存节点
$ rabbitmqctl stop_app
$ rabbitmqctl change_cluster_node_type ram
$ rabbitmqctl start_app
1)RabbitMQ要求在集群中至少有一个磁盘节点,全部其余节点能够是内存节点,当节点加入或者离开集群时,必需要将该变动通知到至少一个磁盘节点。若是集群中惟一的一个磁盘节点崩溃的话,集群仍然能够保持运行,可是没法进行其余操做(增删改查),直到节点恢复, 或者能够设置两个磁盘节点,以保持有一个是可用的。
2)内存节点虽然不写入磁盘,可是它执行比磁盘节点要好。
3)若是集群中只有内存节点,那么不能中止它们,不然全部的状态,消息等都会丢失。

设置镜像队列策略

通过上述配置,集群虽然搭建成功,但只是默认的普通集群,exchange,binding 等数据能够复制到集群各节点。
但对于队列来讲,各节点只有相同的元数据,即队列结构,但队列实体只存在于建立改队列的节点,即队列内容不会复制(从其他节点读取,能够创建临时的通讯传输)。这样此节点宕机后,其他节点没法从宕机节点获取还未消费的消息实体。若是作了持久化,则须要等待宕机节点恢复,期间其他节点不能建立宕机节点已建立过的持久化队列;若是未作持久化,则消息丢失。

下边来配置策略,策略名称为 ha-all,通配符 ^ 表示匹配到的全部队列,复制到全部节点,在任一节点上执行:

$ rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'

也能够复制匹配到的队列到集群中的任意两个或多个节点,而不是到全部节点,并进行自动同步:

$ rabbitmqctl set_policy ha-all "^" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'

或者复制匹配到的队列到集群中的指定节点:

$ rabbitmqctl set_policy ha-all "^" '{"ha-mode":"nodes","ha-params":["rabbit@node01","rabbit@node02"]}'

至此,镜像队列策略配置完成,同时也实现了 HA。

HAProxy 配置

咱们在10.200.100.218主机上直接用 yum 安装 HAProxy 便可:

$ yum -y install haproxy

修改 HAProxy 配置文件 /etc/haproxy/haproxy.cfg以下:

global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    stats socket /var/lib/haproxy/stats

defaults
    mode                    tcp
    log                     global
    option                  tcplog
    option                  dontlognull
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

listen rabbitmq_cluster 0.0.0.0:5670
    mode tcp
    balance roundrobin
    server node1 10.200.100.217:5672 check inter 2000 rise 2 fall 3
    server node2 10.200.100.218:5672 check inter 2000 rise 2 fall 3
    server node3 10.200.100.231:5672 check inter 2000 rise 2 fall 3

listen monitor 0.0.0.0:8100
    mode http
    option httplog
    stats enable
    stats uri /stats
    stats refresh 5s

重启 HAProxy:

$ systemctl restart haproxy.service

以后就能够经过 http://10.200.100.218:8100/stats 查看 HAProxy 的状态了。

若是用的是云主机,能够利用云服务商本身的 LB,不必定要用 HAProxy
相关文章
相关标签/搜索