怎么保证MQ的高可用特性?
使用了MQ之后,我们肯定是希望MQ有高可用特性,因为不可能接受机器宕机了,就无法收发消息的情况。
这一块我们也是基于RabbitMQ这种经典的MQ来说明一下:
RabbitMQ是比较有代表性的,因为是基于主从做高可用性的,我们就以他为例子讲解第一种MQ的高可用性怎么实现。
RabbitMQ有三种模式:
- 单机模式
- 普通集群模式
- 镜像集群模式
单机模式
单机模式就是demo级别的,就是说只有一台机器部署了一个RabbitMQ程序。
这个会存在单点问题,宕机就玩完了,没什么高可用性可言。一般就是你本地启动了玩玩儿的,没人生产用单机模式。
普通集群模式
这个模式的意思就是在多台机器上启动多个RabbitMQ实例。类似的master-slave模式一样。
但是创建的queue,只会放在一个master rabbtimq实例上,其他实例都同步那个接收消息的RabbitMQ元数据。
在消费消息的时候,如果你连接到的RabbitMQ实例不是存放Queue数据的实例,这个时候RabbitMQ就会从存放Queue数据的实例上拉去数据,然后返回给客户端。
总的来说,这种方式有点麻烦,没有做到真正的分布式,每次消费者连接一个实例后拉取数据,如果连接到不是存放queue数据的实例,这个时候会造成额外的性能开销。如果从放Queue的实例拉取,会导致单实例性能瓶颈。
如果放queue的实例宕机了,会导致其他实例无法拉取数据,这个集群都无法消费消息了,没有做到真正的高可用。
所以这个事儿就比较尴尬了,这就没有什么所谓的高可用性可言了,这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个queue的读写操作。
镜像集群模式
镜像集群模式才是真正的RabbitMQ的高可用模式,跟普通集群模式不一样的是:创建的queue无论元数据还是queue里的消息都会存在于多个实例上,
每次写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。
这样的话任何一个机器宕机了别的实例都可以用提供服务,这样就做到了真正的高可用了。
但是也存在着不好之处:
- 性能开销过高,消息需要同步所有机器,会导致网络带宽压力和消耗很重
- 扩展性低:无法解决某个queue数据量特别大的情况,导致queue无法线性拓展。
就算加了机器,那个机器也会包含queue的所有数据,queue的数据没有做到分布式存储。
对于RabbitMQ的高可用一般的做法都是开启镜像集群模式,这样起码来说做到了高可用,一个节点宕机了,其他节点可以继续提供服务。
Reference
- 90%的Java程序员,都扛不住这波消息中间件的面试四连炮! - https://zhuanlan.zhihu.com/p/72728396