[TOC]

RabbitMQ集群

一. 集群架构模式

  1. 主备模式:实现RabbitMQ的高可用集群,一般在并发和数量不高的情况下,这种模型非常的好用且简单.主备模式也称之为Warren模式.
  2. 远程模式:远距离通信和复制,所谓Shovel就是我们可以把消息进行不同数据中心的复制工作,我们可以跨地域让两个mq集群互联
  3. 镜像模式:保证100%数据不丢失,在实际工作中用的最多.
    镜像集群模式图
  4. 多活模式:这种模式也是实现异地数据复制的主流模式,因为Shovel模式配置比较复制,所以一般来说实现异地集群都是使用这种双活或者多活模式来实现的.这种模型需要依赖rabbitmq的federation插件,可以实现持续的可靠的AMQP数据通信,多活模式在实际配置与应用非常的简单.
    • Federation 只接收具有订阅的消息
      多活模式

二. 镜像模式的集群部署

1. 节点说明

服务器 hostname 节点部署程序
192.168.0.115 rabbit3 rabbitmq,Haproxy,keepalived
192.168.0.111 rabbit1 rabbitmq,Haproxy,keepalived
192.168.0.112 rabbit2 rabbitmq,Haproxy,keepalived

1.1 端口及其用途

  • 5672 客户端连接端口。
  • 15672 web管控台端口。
  • 25672 集群通信端口

1.2 节点运行模式

为保证数据持久性,目前所有node节点跑在disk模式,如果今后压力大,需要提高性能,考虑采用ram模式(内存模式)。

1.3 开启防火墙端口

1
2
3
4
firewall-cmd --zone=public --add-port=5672/tcp --permanent
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --zone=public --add-port=25672/tcp --permanent
systemctl restart firewalld.service

2. 创建文件夹和hosts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 111,112,115服务器
# 创建文件夹和hosts
mkdir -p /opt/rabbitmq

# 拷贝插件到主机
docker run -itd --rm --name rabbit-cp rabbitmq:3.7.8-management
docker cp rabbit-cp:/plugins/ /opt/rabbitmq/
docker rm -fv rabbit-cp

cat> /opt/rabbitmq/hosts <<EOF
127.0.0.1 localhost
192.168.50.111 rabbit1 rabbit1
192.168.50.112 rabbit2 rabbit2
192.168.50.115 rabbit3 rabbit3
EOF

3. 执行安装命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 111,112,115服务器,对应的修改--name和--hostname
docker run -d \
--net host \
--name rabbit1 \
--hostname rabbit1 \
--restart=unless-stopped \
--log-opt max-size=10m \
--log-opt max-file=3 \
-v /opt/rabbitmq:/var/lib/rabbitmq:z \
-v /opt/rabbitmq/hosts:/etc/hosts \
-v /etc/localtime:/etc/localtime:ro \
-v /opt/rabbitmq/plugins:/plugins \
-e RABBITMQ_DEFAULT_USER=user \
-e RABBITMQ_DEFAULT_PASS=password \
-e RABBITMQ_ERLANG_COOKIE='0c3fd9eef69b40bdb9d98e4f1e550eb9' \
rabbitmq:3.7.8-management

3.1 命令内容说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#容器的主机名为 rabbit1,容器内部的hostname
--hostname rabbit1
# 不管退出状态码是什么始终重启容器,不过当daemon启动时,如果容器之前已经为停止状态,不要尝试启动它。
--restart=unless-stopped
#日志文件单个最大10M
--log-opt max-size=10m
#日志文件最多保留3个
--log-opt max-file=3
#将宿主机目录/data/rabbitmq挂载到容器的/var/lib/rabbitmq目录。z是一个标记,在selinux环境下使用。
-v /data/rabbitmq:/var/lib/rabbitmq:z
#略
-v /opt/rabbitmq/hosts:/etc/hosts
# 时间同步
-v /etc/localtime:/etc/localtime:ro
# 插件目录
-v /opt/rabbitmq/plugins:/plugins
#设置rabbitmq默认用户为user
-e RABBITMQ_DEFAULT_USER=user
#设置rabbitmq默认密码为password
-e RABBITMQ_DEFAULT_PASS=password
#设置rabbitmq的cookie为“0c3fd9eef69b40bdb9d98e4f1e550eb9”,可以自定义为其他文本,三个容器保持一致即可。
-e RABBITMQ_ERLANG_COOKIE='0c3fd9eef69b40bdb9d98e4f1e550eb9'

4. 组成集群

slave加入集群操作(重新加入集群也是如此,以最开始的主节点为加入节点)

  • 内存模式则将--disc改成--ram
  1. 115 (rabbit3)加入集群

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 进入命令控制台
    docker exec -it rabbit3 /bin/bash
    # 关闭rabbit
    rabbitmqctl stop_app
    # 加入节点配置
    rabbitmqctl join_cluster --disc rabbit@rabbit1
    # 启动rabbit
    rabbitmqctl start_app
    # 退出命令控制台
    exit
  2. 112 (rabbit2)加入集群

    1
    2
    3
    4
    5
    docker exec -it rabbit2 /bin/bash
    rabbitmqctl stop_app
    rabbitmqctl join_cluster --disc rabbit@rabbit1
    rabbitmqctl start_app
    exit

    移除集群节点

    1
    rabbitmqctl forget_cluster_node rabbit@rabbit3

修改集群名称

1
2
# rabbitmq_cluster1则为集群名称
rabbitmqctl set_cluster_name rabbitmq_cluster1

查看集群状态

1
rabbitmqctl cluster_status

5. 配置镜像队列

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

三. 搭建HAProxy(负载均衡)

端口及用途

  • 5669 Haproxy的统计web界面
  • 5668 rabbitmq的视图界面
  • 5667 rabbitmq的集群端口5672的入口
  • 4369 集群建立连接端口
  • Haproxy的统计web界面地址 : http://ip:5669/haproxy?stats

开启防火墙端口

1
2
3
4
5
firewall-cmd --zone=public --add-port=5667/tcp --permanent
firewall-cmd --zone=public --add-port=5668/tcp --permanent
firewall-cmd --zone=public --add-port=5669/tcp --permanent
firewall-cmd --zone=public --add-port=4369/tcp --permanent
systemctl restart firewalld.service

1. 创建haproxy.cfg配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 111,112,115服务器
# 创建文件夹和haproxy.cfg
mkdir -p /opt/haproxy

cat> /opt/haproxy/haproxy.cfg <<EOF
global
maxconn 10000 #默认最大连接数
log 127.0.0.1 local0 #[err warning info debug]
chroot /usr/local/sbin #chroot运行的路径
daemon #以后台形式运行haproxy
pidfile /var/run/haproxy.pid #haproxy的pid存放路径,启动进程的用户必须有权限访问此文件
defaults
log 127.0.0.1 local3
mode http #所处理的类别 (#7层 http;4层tcp )
maxconn 10000 #最大连接数
option dontlognull #不记录健康检查的日志信息
option redispatch #serverId对应的服务器挂掉后,强制定向到其他健康的服务器
#stats refresh 30 #统计页面刷新间隔
retries 3 #3次连接失败就认为服务不可用,也可以通过后面设置
balance roundrobin #默认的负载均衡的方式,轮询方式
#balance source #默认的负载均衡的方式,类似nginx的ip_hash
#balance leastconn #默认的负载均衡的方式,最小连接
timeout connect 5000 #连接超时
timeout client 50000 #客户端超时
timeout server 50000 #服务器超时
timeout check 2000 #心跳检测超时
####################################################################
listen http_front
bind 0.0.0.0:5669 #监听端口
stats refresh 10s #统计页面自动刷新时间
stats uri /haproxy?stats #统计页面url
stats realm Haproxy Manager #统计页面密码框上提示文本
stats auth admin:admin #统计页面用户名和密码设置
#stats hide-version #隐藏统计页面上HAProxy的版本信息
#####################我把RabbitMQ的管理界面也放在HAProxy后面了###############################
listen rabbitmq_admin
bind 0.0.0.0:5668
server rabbit3 192.168.50.115:15672
server rabbit2 192.168.50.112:15672
server rabbit1 192.168.50.111:15672
####################################################################
listen rabbitmq_cluster
bind 0.0.0.0:5667
option tcplog
mode tcp
timeout client 3h
timeout server 3h
option clitcpka
balance roundrobin #负载均衡算法(#banlance roundrobin 轮询,balance source 保存session值,支持static-rr,leastconn,first,uri等参数)
#balance url_param userid
#balance url_param session_id check_post 64
#balance hdr(User-Agent)
#balance hdr(host)
#balance hdr(Host) use_domain_only
#balance rdp-cookie
#balance leastconn
#balance source //ip
server rabbit3 192.168.50.115:5672 check inter 5s rise 2 fall 3 #check inter 2000 是检测心跳频率,rise 2是2次正确认为服务器可用,fall 3是3次失败认为服务器不可用
server rabbit2 192.168.50.112:5672 check inter 5s rise 2 fall 3
server rabbit1 192.168.50.111:5672 check inter 5s rise 2 fall 3

EOF

2. 启动Haproxy

1
2
3
4
5
6
7
8
9
docker run -d \
--privileged \
--name haproxy \
--restart=unless-stopped \
-p 5667:5667 \
-p 5668:5668 \
-p 5669:5669 \
-v /opt/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg \
haproxy:1.9.2-alpine

四. 搭建KeepAlived

1. 创建配置文件

  1. 主节点:192.168.50.111

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    mkdir -p /opt/keepalived

    cat>/opt/keepalived/keepalived.conf<<EOF
    vrrp_instance VI_1 {
    state MASTER ## 主节点为MASTER,备份节点为BACKUP
    interface ens33 ## 绑定虚拟IP的网络接口(网卡),与本机IP地址所在的网络接口相同(服务器主机网卡)
    virtual_router_id 111 ## 虚拟路由ID号(主备节点一定要相同)
    mcast_src_ip 192.168.50.111 ## 本机ip地址
    priority 100 ##优先级配置(0-254的值)
    nopreempt
    advert_int 1 ## 组播信息发送间隔,俩个节点必须配置一致,默认1s
    authentication { ## 认证匹配
    auth_type PASS
    auth_pass rabbitmq
    }

    virtual_ipaddress {
    192.168.50.28 ## 虚拟ip,可以指定多个
    }
    }

    EOF

  2. 备份节点:192.168.50.112

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    mkdir -p /opt/keepalived

    cat>/opt/keepalived/keepalived.conf<<EOF
    vrrp_instance VI_1 {
    state BACKUP ## 主节点为MASTER,备份节点为BACKUP
    interface ens33 ## 绑定虚拟IP的网络接口(网卡),与本机IP地址所在的网络接口相同(服务器主机网卡)
    virtual_router_id 111 ## 虚拟路由ID号(主备节点一定要相同)
    mcast_src_ip 192.168.50.112 ## 本机ip地址
    priority 100 ##优先级配置(0-254的值)
    nopreempt
    advert_int 1 ## 组播信息发送间隔,俩个节点必须配置一致,默认1s
    authentication { ## 认证匹配
    auth_type PASS
    auth_pass rabbitmq
    }

    virtual_ipaddress {
    192.168.50.28 ## 虚拟ip,可以指定多个
    }
    }

    EOF
  3. 备份节点:192.168.50.115

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mkdir -p /opt/keepalived

cat>/opt/keepalived/keepalived.conf<<EOF
vrrp_instance VI_1 {
state BACKUP ## 主节点为MASTER,备份节点为BACKUP
interface ens33 ## 绑定虚拟IP的网络接口(网卡),与本机IP地址所在的网络接口相同(服务器主机网卡)
virtual_router_id 111 ## 虚拟路由ID号(主备节点一定要相同)
mcast_src_ip 192.168.50.115 ## 本机ip地址
priority 100 ##优先级配置(0-254的值)
nopreempt
advert_int 1 ## 组播信息发送间隔,俩个节点必须配置一致,默认1s
authentication { ## 认证匹配
auth_type PASS
auth_pass rabbitmq
}

virtual_ipaddress {
192.168.50.28 ## 虚拟ip,可以指定多个
}
}

EOF

2. 启动keepalived

1
2
3
4
5
6
docker run -d --net=host \
--privileged \
--name keepalived \
--restart=unless-stopped \
-v /opt/keepalived/keepalived.conf:/container/service/keepalived/assets/keepalived.conf \
osixia/keepalived --copy-service

五 集群配置文件

  • 关键配置参数:
    1. tcp_listerners 设置rabbitmq的监听端口,默认为[5672]
    2. disk_free_limit 磁盘低水位线,若磁盘容量低于指定值则停止接收数据,默认值为{mem_relative,1.0},即与内存相关联1:1,也可以定制为多少byte.
    3. vm_memory_high_watermark,设置内存低水位线,若低于该水位线,则开启流控机制,默认值0.4,即内存总量的40%.
    4. hipe_com批了将部分rabbitmq代码用High Performance Erlang compile编译,可提升性能,该参数是实验性,若出现erlang vmsegfaults,应该关掉.
    5. force_fine_statistics,该参数属于rabbitmq_management,若为true则进行精细化的统计,但会影响性能
    6. 集群节点模式:Disk为磁盘存储/ram为内存存储
    7. 更详细的配置参见:http://www.rabbitmq.com/configure.html

六 集群恢复与故障转移

  • B为主节点(Master),A为备份节点(Salve)

1. 场景1: A先停,B后停

  • 解决方法:只要先启动B,在启动A即可.或者先启动A,在30秒之内启动B即可恢复镜像队列

2. 场景2: A,B同时停机

  • 解决方法:只需在30秒之内连续启动A和B即可恢复镜像

3. 场景3: A先停,B后停,且A无法恢复

  • 解决方法: 先启动B,然后在B节点上调用控制台命令:rabbitmqctl forget_cluster_node A 解除与A的Cluster关系,在将新的Slave节点加入B即可重新恢复镜像队列

4. 场景4: A先停,B后停,且B无法恢复

  • 解决方法: 在A节点执行rabbitmqctl forget_cluster_node -offline B时,rabbitmq会mock一个节点代表A,自动执行forget_cluster_node命令将B剔除cluster,然后A就可以正常启动了,最后将新的Slave节点加入A即可重新恢复镜像队列

5. 场景5: A先停,B后停,且A,B均无法恢复,但是能得到A或B的磁盘文件

  • 解决方法: 将A或B的数据库文件默认在$RABBIT_HOME/var/lib/目录中,把它拷贝到新节点的对应目录下,在将新节点的hostname改成A或B的hostname,如果是A节点的磁盘文件,则按照场景4处理即可,如果是B节点的磁盘文件,则按照场景3处理,最后将新的slave加入到新节点后完成恢复

七 制定扩展

  • 插件搜索下载地址:http://www.rabbitmq.com/community-plugins.html
  1. 延迟队列插件
  • 延迟插件名称:rabbitmq_delayed_message_exchange
  • ***.ez放入/opt/rabbitmq/plugins目录下(rabbit1,rabbit2,rabbit3)
  • 重命名插件名称rabbitmq_delayed_message_exchange-0.0.1.ez
  • 进入docker rabbitmq 的命令行,启动插件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # rabbit1
    docker exec -it rabbit1 /bin/bash
    rabbitmq-plugins enable rabbitmq_delayed_message_exchange

    # rabbit2
    docker exec -it rabbit2 /bin/bash
    rabbitmq-plugins enable rabbitmq_delayed_message_exchange

    # rabbit3
    docker exec -it rabbit3 /bin/bash
    rabbitmq-plugins enable rabbitmq_delayed_message_exchange
  • ps: 关闭指定插件的命令
    1
    rabbitmq-plugins disable rabbitmq_delayed_message_exchange