RabbitMQ 入门系列(7)— 如何保证 RabbitMQ 高可用性(单机模式、普通集群模式、镜像集群模式)

RabbitMQ 有三种模式:单机模式,普通集群模式,镜像集群模式:

1.单机模式

单机模式就是说只有一台机器部署了一个 RabbitMQ 程序。这台机器宕机后就玩不转了。

2.普通集群模式

这个模式的意思就是在多台机器上启动多个 RabbitMQ 实例。类似的 master-slave 模式一样。但是创建的 queue,只会放在一个 master rabbtimq 实例上,其他实例都同步那个接收消息的 RabbitMQ 元数据。

在消费消息的时候,如果你连接到的 RabbitMQ 实例不是存放 queue 数据的实例,这个时候 RabbitMQ 就会从存放 queue 数据的实例上拉去数据,然后返回给客户端。

总的来说,这种方式有点麻烦,没有做到真正的分布式,每次消费者连接一个实例后拉取数据,如果连接到不是存放 queue 数据的实例,这个时候会造成额外的性能开销。如果从放 queue 的实例拉取,会导致单实例性能瓶颈。

如果放 queue 的实例宕机了,会导致其他实例无法拉取数据,这个集群都无法消费消息了,没有做到真正的高可用。

所以这个事儿就比较尴尬了,这就没有什么所谓的高可用性可言了,这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个 queue 的读写操作。

3.镜像集群模式

镜像集群模式才是真正的 RabbitMQ 的高可用模式,跟普通集群模式不一样的是:创建的 queue 无论元数据还是 queue 里的消息都会存在于多个实例上,每次写消息到 queue 的时候,都会自动把消息到多个实例的 queue 里进行消息同步。

这样的话任何一个机器宕机了别的实例都可以用提供服务,这样就做到了真正的高可用了。

但是也存在着不好之处:

  • 性能开销过高,消息需要同步所有机器,会导致网络带宽压力和消耗很重
  • 扩展性低:无法解决某个 queue 数据量特别大的情况,导致 queue 无法线性拓展。就算加了机器,那个机器也会包含 queue 的所有数据,queue 的数据没有做到分布式存储。

对于 RabbitMQ 的高可用一般的做法都是开启镜像集群模式,这样起码来说做到了高可用,一个节点宕机了,其他节点可以继续提供服务。

4. 集群架构

4.1 为什么使用集群

内建集群作为 RabbitMQ 最优秀的功能之一,它的作用有两个:

  1. 允许消费者和生产者在 Rabbit 节点崩溃的情况下继续运行;
  2. 通过增加节点来扩展 Rabbit 处理更多的消息,承载更多的业务量;

4.2 集群的特点

RabbitMQ 的集群是由多个节点组成的,但我们发现不是每个节点都有所有队列的完全拷贝。

为什么默认情况下 RabbitMQ 不将所有队列内容和状态复制到所有节点?
有两个原因:

  1. 存储空间——如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据。
  2. 性能——如果消息的发布需安全拷贝到每一个集群节点,那么新增节点对网络和磁盘负载都会有增加,这样违背了建立集群的初衷,新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。
    所以其他非所有者节点只知道队列的元数据,和指向该队列节点的指针。

4.3 集群异常处理

根据节点不无安全拷贝的特性,当集群节点崩溃时,该节点队列和关联的绑定就都丢失了,附加在该队列的消费者丢失了其订阅的信息,那么怎么处理这个问题呢?
这个问题要分为两种情况:

  1. 消息已经进行了持久化,那么当节点恢复,消息也恢复了;
  2. 消息未持久化,可以使用下文要介绍的双活冗余队列,镜像队列保证消息的可靠性;

4.4 集群节点类型

节点的存储类型分为两种:
● 磁盘节点
● 内存节点

磁盘节点就是配置信息和元信息存储在磁盘上,内存节点把这些信息存储在内存中,当然内存节点的性能是大大超越磁盘节点的。

单节点系统必须是磁盘节点,否则每次你重启 RabbitMQ 之后所有的系统配置信息都会丢失。RabbitMQ 要求集群中至少有一个磁盘节点,当节点加入和离开集群时,必须通知磁盘节点。

特殊异常:集群中唯一的磁盘节点崩溃了
如果集群中的唯一一个磁盘节点,结果这个磁盘节点还崩溃了,那会发生什么情况?如果唯一磁盘的磁盘节点崩溃了,不能进行如下操作:
● 不能创建队列
● 不能创建交换器
● 不能创建绑定
● 不能添加用户
● 不能更改权限
● 不能添加和删除集群几点

总结:如果唯一磁盘的磁盘节点崩溃,集群是可以保持运行的,但你不能更改任何东西。
解决方案:在集群中设置两个磁盘节点,只要一个可以,你就能正常操作。

5. 集群搭建方法

5.1 安装多个 RabbitMQ

docker run -d --hostname rabbit1 --name myrabbit1 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management

docker run -d --hostname rabbit2 --name myrabbit2 -p 5673:5672 --link myrabbit1:rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management

docker run -d --hostname rabbit3 --name myrabbit3 -p 5674:5672 --link myrabbit1:rabbit1 --link myrabbit2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management

注意点:

  1. 多个容器之间使用 --link 连接,此属性不能少;
  2. Erlang Cookie 值必须相同,也就是 RABBITMQ_ ERLANG_ COOKIE 参数的值必须相同;

5.2 加入 RabbitMQ 节点到集群

设置节点1:

docker exec -it myrabbit1 bash rabbitmqctl stopapp rabbitmqctl reset rabbitmqctl startapp exit

设置节点 2,加入到集群:

docker exec -it myrabbit2 bash rabbitmqctl stopapp rabbitmqctl reset rabbitmqctl joincluster --ram rabbit@rabbit1 rabbitmqctl start_app exit

设置节点 3,加入到集群:

docker exec -it myrabbit3 bash rabbitmqctl stopapp rabbitmqctl reset rabbitmqctl joincluster --ram rabbit@rabbit1 rabbitmqctl start_app exit

设置好之后,使用 http://物理机 ip:15672 进行访问了,默认账号密码是 guest/guest,效果如下图:
mq到此为止,我们已经完成了 RabbitMQ 集群的建立,启动了 3 个节点,1 个磁盘节点和 2 个内存节点。

  • 设置节点类型

如果你想更换节点类型可以通过命令修改,如下:

rabbitmqctl stop_app
rabbitmqctl changeclusternode_type dist
rabbitmqctl changeclusternode_type ram
rabbitmqctl start_app
  • 移除节点

如果想要把节点从集群中移除,可使用如下命令实现:

rabbitmqctl stop_app
rabbitmqctl restart
rabbitmqctl start_app
  • 集群重启顺序

集群重启的顺序是固定的,并且是相反的。
如下所述:
● 启动顺序:磁盘节点 => 内存节点
● 关闭顺序:内存节点 => 磁盘节点

最后关闭必须是磁盘节点,不然可能回造成集群启动失败、数据丢失等异常情况。

参考

https://gitbook.cn/books/5d65124b2b27dd24ed390665/index.html
https://www.cnblogs.com/vipstone/p/9362388.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值