开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情
RabbitMQ 集群
如何实现高可用:集群+镜像+haproxy+keepalive
RabbitMQ 內建集群
內建集群的设计目标
1、允许消费者和生产者在节点崩溃的情况下继续运行; 2、通过添加节点线性扩展消息通信的吞吐量。
可以保证消息的万无一失吗? 不行,当一个节点崩溃时,该节点上队列的消息也会消失,rabbitmq 默认不会将队列的消息复制到整个集群上。
集群中的队列和交换器
队列
集群中队列信息只在队列的所有者节点保存队列的所有信息,其他节点只知道队列的元数据和指向所有者节点的指针,节点崩溃时,该节点的队列和其上的绑定信息都消失了。
为什么集群不复制队列内容和状态到所有节点:1)存储空间;2)性能,如果消息需要复制到集群中每个节点,网络开销不可避免,持久化消息还需要写磁盘。
所以其他节点接收到不属于该节点的队列的消息时会将该消息传递给该队列的所有者节点上。
交换器
本质上是个这个交换器的名称和队列的绑定列表,可以看成一个类似于 hashmap 的映射表,所以交换器会在整个集群上复制。
元数据
- 队列元数据:队列名称和属性(是否可持久化,是否自动删除)
- 交换器元数据:交换器名称、类型和属性
- 绑定元数据:交换器和队列的绑定列表
- vhost 元数据:vhost 内的相关属性,如安全属性等等
集群中的节点
要么是内存节点,要么是磁盘节点。怎么区分?就是节点将队列、交换器、用户等等信息保存在哪里?单节点肯定是磁盘类型。集群中可以有内存节点,为了性能的考虑,全部是磁盘节点,当声明队列、交换器等等时,rabbitmq 必须将数据保存在所有节点后才能表示操作完成。
Rabbitmq 只要求集群中至少有一个磁盘节点,从高可用的角度讲每个集群应该至少配备两个磁盘节点。因为只有一个磁盘节点的情况下,当这个磁盘节点崩溃时,集群可以保持运行,但任何修改操作,比如创建队列、交换器、添加和删除集群节点都无法进行。
构建我们自己的集群
集群常用命令:
- rabbitmqctl join_cluster [rabbit@node1]将节点加入集群
- rabbitmqctl cluster_status 查询集群状态
- rabbitmqctl reset 严格来说,不属于集群命令,reset 的作用是将 node 节点恢复为空白状态,包括但不限于,比如,用户信息,虚拟主机信息,所有持久化的消息。在集群下,通过这个命令,可以让节点离开集群。
集群下的注意事项
元数据的变更,我们知道,这些消息都要记录在磁盘节点上。当有节点离开集群时,所有的磁盘节点上都要记录这个信息。如果磁盘节点在离开集 群时不用 reset 命令,会导致集群认为该节点发生了故障,并会一直等待该节点恢复才允许新节点加入,所以,当磁盘节点是被暴力从集群中脱离时,有 可能导致集群永久性的无法变更(不单单是加入新节点,包括申明队列,交换器等操作)
RabbitMQ 集群高可用
镜像队列
什么是镜像队列
如果 RabbitMQ 集群是由多个 broker 节点构成的,那么从服务的整体可用性上来讲,该集群对于单点失效是有弹性的,但是同时也需要注意:尽管 exchange 和 binding 能够在单点失效问题上幸免于难,但是 queue 和其上持有的 message 却不行,这是因为 queue 及其内容仅仅存储于单个节点之上,所以一个节点的失效表现为其对应的 queue 不可用。
引入 RabbitMQ 的镜像队列机制,将 queue 镜像到 cluster 中其他的节点之上。在该实现下,如果集群中的一个节点失效了,queue 能自动地切换到镜 像中的另一个节点以保证服务的可用性。在通常的用法中,针对每一个镜像队列都包含一个 master 和多个 slave,分别对应于不同的节点。slave 会准确地 按照 master 执行命令的顺序进行命令执行,故 slave 与 master 上维护的状态应该是相同的。除了 publish 外所有动作都只会向 master 发送,然后由 master 将命令执行的结果广播给 slave 们,故看似从镜像队列中的消费操作实际上是在 master上执行的。
RabbitMQ 的镜像队列同时支持 publisher confirm 和事务两种机制。在事务机制中,只有当前事务在全部镜像 queue 中执行之后,客户端才会收到 Tx.CommitOk 的消息。同样的,在 publisher confirm 机制中,向 publisher 进行当前 message 确认的前提是该 message 被全部镜像所接受了。
镜像队列的配置
代码 :
Map args = new HashMap(); args.put("x-ha-policy", "all");
在声明队列时传入 channel.queueDeclare(queueName,false,false, false, args);
控制台
镜像队列的配置通过添加 policy 完成,policy 添加的命令为:
- rabbitmqctl 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。
- ha-mode:指明镜像队列的模式,有效值为 all/exactly/nodes
- priority:可选参数,policy 的优先级 例如,对队列名称以“queue_”开头的所有队列进行镜像,并在集群的两个节点上完成进行,policy 的设置命令为: rabbitmqctl set_policy ha-queue-two"^queue_" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}' windows 下将单引号改为双引号(rabbitmqctl set_policy ha-all “^ha.” “{“”ha-mode”“:”“all”“}”)
补充: 可通过如下命令确认哪些 salve 在同步:
- rabbitmqctl list_queues name slave_pids synchronised_slave_pids
- 手动同步 queue: rabbitmqctl sync_queue name
- 取消 queue 同步: rabbitmqctl cancel_sync_queue nam
使用 HAProxy 处理节点选择,故障服务器检测和负载分布可以使用 HAProxy。
============下载并解压============
cd /usr/local/src/
wget http://pkgs.fedoraproject.org/repo/pkgs/haproxy/haproxy-1.7.9.tar.gz/sha512/d1ed791bc9607dbeabcfc6a1853cf258e28b3a079923b63d3bf97504dd59e64a5f5f44f9da968c23c12b4279e8d45ff3bd39418942ca6f00d9d548c9a0ccfd73/haproxy-1.7.9.tar.gz
tar zxvf haproxy-1.7.9.tar.gz
============安装============
cd haproxy-1.7.9
uname -r
3.10.0-514.el7.x86_64
make TARGET=linux310 ARCH=x86_64 PREFIX=/usr/local/haproxy
make install PREFIX=/usr/local/haproxy
==参数说明:
==TARGET=linux310,内核版本,使用uname -r查看内核,如:3.10.0-514.el7,此时该参数就为linux310;kernel ==大于2.6.28的可以用:TARGET=linux2628;
==ARCH=x86_64,系统位数;
==PREFIX=/usr/local/haprpxy #/usr/local/haprpxy,为haprpxy安装路径。
============添加配置文件============
cd /usr/local/haproxy
mkdir conf
cd conf/
vim haproxy.cfg
global
log 127.0.0.1 local0
maxconn 1000
daemon
defaults
log global
mode http
option httplog
option dontlognull
retries 3
timeout connect 5000
timeout client 50000
timeout server 50000
listen admin_stats
bind 0.0.0.0:1080
mode http
option httplog
maxconn 10
stats refresh 30s
stats uri /stats
stats realm XingCloud\ Haproxy
stats auth admin:admin
stats auth Frank:Frank
stats hide-version
stats admin if TRUE
listen rabbitmq_cluster
bind 0.0.0.0:5670
mode tcp
balance roundrobin
server rabbit01 127.0.0.1:5672 check inter 5000 rise 2 fall 3
server rabbit02 node2:5672 check inter 5000 rise 2 fall 3
============启动haproxy============
/usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/conf/haproxy.cfg
============验证============
lsof -i :1080
============访问统计页面============
http://127.0.0.1:1080/stats
参考资料: 享学课堂king老师