保证消息队列的高可用性

在实际生产中,引入消息队列技术固然会带来好处,比如降低系统耦合、异步提高响应速度、削平高峰期压力等。然而,任何技术都是一把双刃剑,引入消息队列的同时就要承担一定的风险:系统引入的外部依赖越多,越容易出问题。一旦消息中间件宕机,就会导致整个系统无法使用。因此,保证消息队列的高可用性非常重要。

怎么保证MQ的高可用?

RabbitMQ的高可用模式

RabbitMQ保证高可用有三种模式:单机模式,普通集群模式,镜像集群模式

  • 单机模式

    测试环境下供开发者使用,不适用生产环境

  • 普通集群模式

    在集群环境下部署多个MQ,但创建的消息队列(queue)会集中置于一个MQ实例中,其他每个实例同步该消息队列的元数据(可以理解为配置文件,但不是消息本身)。当消费者需要拉取消息时,如果并没有连接到消息队列所在实例,那么该实例会到消息队列所在实例上拉取消息

    普通集群模式的弊端:

    1. 可能会在MQ集群内部产生大量数据传输,系统开销较大
    2. 可用性较低。一旦queue所在实例挂掉,消息就会丢失,消费者无法正常消费
  • 镜像集群模式

    在这种模式下,创建的消息队列无论元数据还是消息队列中的消息都会存在于多个实例上,然后每次当生产者发送消息给MQ实例时,都会自动把消息发送到多个实例的消息队列中进行消息同步。

    如何开启镜像集群模式?

    在上一篇文章中提到,RabbitMQ有很好的管理控制台,只需要在后台新增一个镜像集群模式的策略,命令数据同步到所有或指定数量的MQ实例中,当生产者再次创建消息队列时应用这个策略,即可自动同步数据到其他实例中。

    镜像集群模式的优势:

    高可用。MQ集群中任何一台机器挂了都没事,有备用机器。

    镜像集群模式的弊端:

    1. 由于RabbitMQ不支持分布式集群,消息队列同步到所有MQ实例会增大网络带宽压力,系统性能开销也相应提高
    2. 扩展性不好。无法线性扩展消息队列,一旦在集群中增加机器,就要同步所有消息队列中的数据。

Kafka的高可用模式

Kafka集群由多个Kafka实例构成,每个实例被称为broker,每个broker是一个节点;当生产者创建一个topic时,这个topic可以划分为多个partition(区),每个partition可以存在于不同的broker上,每个partition就放一部分数据。

上述模式是天然的分布式消息队列,即一个 topic 的数据,分布在不同的MQ上,每台MQ只放一部分数据

实际上 RabbmitMQ 不是分布式消息队列,它只是提供了一些集群、HA(High Availability, 高可用性) 机制的传统消息队列。

Kafka 0.8 以前,是没有 HA 机制的,任何一个 broker 宕机了会导致 broker 上的 partition 就挂掉,无法读写,没有什么高可用性可言。

Kafka 0.8 以后,提供了 HA 机制,即 replica(复制品) 副本机制。每个 partition 的数据都会同步到其它机器上,形成自己的多个 replica 副本。所有 replica 会选举一个 leader 出来,那么生产和消费都跟这个 leader 打交道,然后其他 replica 被称为 follower写的时候,leader 会负责把数据同步到所有 follower 上去,读的时候就直接读 leader 上的数据即可。只能读写 leader?很简单,要是你可以随意读写每个 follower,那么就要解决数据一致性的问题,系统复杂度太高,很容易出问题。Kafka 会均匀地将一个 partition 的所有 replica 分布在不同的机器上,保证了高可用。

如此一来,就保证了消息队列的高可用。每个 broker 中的 partition 在其他机器上都有副本,因此不用担心某个 broker 宕机。如果宕机的 broker 中有某个 partition 的 leader,那么此时会从 follower 中重新选举一个新的 leader 出来,大家继续读写新的 leader 即可。这就是Kafka实现高可用的模式。

生产者写消息时,生产者就写 leader,然后 leader 将数据写入本地磁盘,接着其他 follower 自己主动从 leader 来 pull 数据。一旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。(当然,这只是其中一种模式,还可以适当调整这个行为)

消费者消费消息时,只会从 leader 去读,但是只有当一个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。

总结

本文主要介绍了RabbitMQ和Kafka保证高可用的模式。

RabbitMQ保证高可用有三种模式:普通模式、普通集群模式和镜像集群模式。

其中,普通集群的消息队列只存在于一台机器上,因此当需要拉取消息时,会产生大量数据传输,系统开销大

相对于普通集群模式,镜像集群模式则把消息队列保存在多台服务器上,虽然保证了高可用但由于只是简单的集群,不是分布式系统,增加了系统开销,且扩展性不好

Kafka支持分布式,在0.8前没有高可用机制,0.8后提供了 replica 副本机制很好地保证了消息队列的高可用性。每个机器上的partition在其他机器上都有副本,且每个partition都有一个leader,其他机器为follower,生产者和消费者只会在leader上进行读写操作,当leader挂掉时,会重新从follower中选举一个新的leader,不会影响读写。

注:本系列文章是来自中华石杉老师课程的整理和总结。






欢迎关注微信公众号,一起交流技术↓

{mywechat}

0%