【消息队列】2-如何保证消息队列的高可用?

avatar 2020年11月16日19:01:56 0 64 views

如果面试官问我们如何保证消息队列的高可用?我们可以说其中一个自己熟悉的MQ去跟他讲。

所谓MQ高可用无非是MQ挂了,怎么保证数据不丢失,系统正常运行。一般都是通过搭建集群模式来做,数据会有副本。

 

一、RabbitMQ高可用

RabbitMQ有两种集群模式:普通集群和镜像集群模式。

1. 普通集群(不高可用)

在多个服务器上各安装一个RabbitMQ,通过内部命令或配置来构建集群。创建的queue只会在其中一台实例上,但是每个实例会相互同步元数据(queue的配置信息,可以通过元数据找到queue所在的实例)。用户只需要连接到任意一个实例就可以监听消费对应队列上的所有数据。

 

比如有三台实例A、B、C,某个消费者监听的队列queue在B实例上,但是消费者连接的Broker是A实例,所以需要根据A实例的元数据去找队列的位置,然后再去拿数据,返回给消费者。

 

缺点:

  • RabbitMQ内部频繁传输数据,比较浪费资源
  • 如果其中一个实例挂了,那么这个实例上的数据,用户请求这个实例就获取不到数据了。

 

2. 镜像集群模式(高可用性)

为了解决普通模式的两个缺点,镜像模式做了改进。

生产者创建队列或推送消息数据都会同步到其他实例上,每个实例上都有相同的数据。当一台实例挂了,不影响消息的消费。

 

缺点:

  • 同步数据性能开销很大
  • 不能扩展,每台实例数据一样的,不能通过增加实例来解决

 

二、RocketMQ高可用

RocketMq集群由NameServer和Broker两种角色组成,NameServer是无状态, 可用部署多台组成NameServer集群,非常简单,NameServer里面存储的元数据信息(里面有Topc和Queue信息,Broker状态信息等)。

Broker集群分为单Master、多Master、多Master多Slave异步和多Master多Slave同步几种。

可以理解,每个 Broker 就是一台实例,用于存储数据。

集群模式中,每个 topic 分布在多台Broker上,即多个Topic分片,分片的目的就是利于水平扩展),创建Topic时,可以指定队列数,Topic的消息会分布在某一个队列上。 消费者数量需要小于队列数量,否则多出来的消费者没有队列可以去拉消息。

RocketMQ有如下几种部署模式

1. 单Master模式

单机版,生产不建议使用

  • 优点:除了配置简单没什么优点
  • 缺点:不可靠,该机器重启或宕机,将导致整个服务不可用

 

2. 多Master模式

全是Master,无Slave。某个实例挂了,该实例在重启前未被消费的消息无法被消费

  • 优点:配置简单,性能最高
  • 缺点:单台机器重启或宕机期间,该机器下未被消费的消息在机器恢复前不可订阅,影响消息实时性

 

3. 多Master多Slave异步模式

每个Master配一个Slave,有多对Master-Slave,集群采用异步复制方式,主备有短暂消息延迟,毫秒级

  • 优点:性能同多Master几乎一样,实时性高,主备间切换对应用透明,不需人工干预
  • 缺点:Master宕机或磁盘损坏时会有少量消息丢失

 

4. 多Master多Slave同步模式

每个Master配一个Slave,有多对Master-Slave,集群采用同步双写方式,主备都写成功,才向应用返回成功

  • 优点:服务可用性与数据可用性非常高
  • 缺点:性能比异步集群略低,当前版本主宕备不能自动切换为主

需要注意的是,在RocketMQ里面,1台机器只能要么是Master,要么是Slave。这个在初始的机器配置里面,就定死了。

其中Master的broker id = 0,Slave的broker id > 0。有点类似于mysql的主从概念,Master挂了以后,Slave仍然可以提供读服务,但是由于有多主的存在,当一个Master挂了以后,可以写到其他的Master上。

 

三、Kafka高可用

kafka跟rocketmq很相似,不对,应该是rocketmq像kafka

kafka集群的话是 zookeeper集群+broker集群,我们这里主要说 broker。

创建一个 topic,会有几个Partition(分片),Partition会分布在多个broker上,通常Partition数量>broker数量。

如果某个Partition所在的broker挂了,那么这个Partition上的未被消费的消息将暂时不能被消费。

为了解决这个问题,就需要给Partition复制多份副本,从而保证某一个Partition所在的broker挂了,依然可以被消费消息。

我们叫他 Replica (副本),Replica会有多个,其中一个是Leader,剩下的为Follow。

 

生产者生产消息时,会往某个Partition里写入消息数据,只往 Leader  Replica 写入数据,然后 Follow Replica 会从其 Leader Replica 那里同步新数据,当所有的Follow通知Leader都同步好数据了,Partition 才会告诉生产者生产消息成功(这是一种策略,可以配置修改)。

 

消费者消费消息时,同理,只从 Leader Replica 拿数据,然后 Follow Replica 会从其 Leader Replica 那里同步新数据,当所有的Follow通知Leader都同步好数据了,Partition 才会告诉消费者消费消息成功(这是一种策略,可以配置修改)。

 

 

  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
avatar

发表评论

avatar 登录者:匿名
您需要登录才能评论,可以选择注册或者QQ快速登录

     

已通过评论:0   待审核评论数:0