面向面试编程:消息队列——高可用

178 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

面试官:引入消息队列后如何保证消息队列的高可用?

RabbitMQ的高可用

普通集群模式

假设rabbitMQ集群有三台机器,每台机器都启动了一个进程作为集群中的一个节点,但是创建的queue只会放在一个rabbitMQ实例上,其他实例都同步queue的元数据(它知道queue在哪),消费者消费时,如果连接到了另一个实例,那么他会从queue所在的实例上拉取数据过来,这个方案没有什么高可用性科研了,主要是提高吞吐量,让集群中多个节点来服务某个queue的读写操作。缺点有两个,一是可能会在rabbitMQ内部产生大量的数据传输,二是可用性几乎没什么保障,如果queue所在的节点宕机了导致queue的数据丢失了,就无法消费了。

镜像集群模式

每个节点都有一个queue的完整镜像,包含这个queue的全部数据,所以叫镜像集群模式。任何一个节点宕机,其他节点上还包含了这个queue的全部数据,消费者可以到其他节点去消费数据。缺点,不是分布式的。

kafka的高可用性

kafka最基本的架构知识:多个broker组成,每个broker是一个节点,创建一个topic,这个topic可以划分为多个partition,每个partition可以存放在不同的broker上,每个partition就存放一部分数据,kafka0.8以后提供了HA机制,replica副本机制,每个partition的数据都会同步到其他机器上,形成自己的replica副本。然后所有的replica会选举一个leader出来,生产者和消费者都跟这个leader打交道,其他replica为follower。写的时候,leader会将数据同步到follower,kafka会将一个partition的所有replica分布在不同的机器上提高容错性,如果某个broker宕机,那么broker上面的partition在其他机器上的副本都有的,如果这个机器上有某个partition的leader,那么此时会重新选举一个新的leader出来,大家继续读写那个新的leader即可,实现高可用。

写数据的时候,生产者只写leader,leader在将数据落地本地磁盘,接着其他follower自动从leader来pull数据,一旦所有follower同步好数据了,就会发送ack费leader,leader收到所有follower的ack之后,就会返回写成功的消息给生产者,消费的时候只会从leader读,只有一个消息已经被所有follower都同步成功返回ack时,才会被消费者读到。

RocketMQ

集群化部署

假设RockerMQ部署在一台机器上,即使这台机器配置很高,但是一般来说一台机器也就是支撑10万左右的并发访问。那么这个时候,假设有大量的系统都要往RocketMQ里并发写入消息,每秒几十万请求,这时该怎么办?

RocketMQ是可以集群化部署的,可以部署在多台机器上,只要将几十万请求分散到多台机器上就可以了。

存储海量消息

MQ会收到大量的消息,这些消息并不是立马被消费者获取去消费的,所以一般MQ都会把消息在自己本地磁盘存储起来,然后等待消费方获取消息去消费。

既然如此,MQ就得存储大量的消息,几百万条到几亿条不等,这么多的消息在一台机器上肯定是没法存储的。

其实发送消息到MQ的系统会把消息分散发送给多台不同的机器,一万条消息分散给十台机器,每台机器就是一千条消息。

每台机器上的RocketMQ进程一般称之为broker,每个broker会收到不同的消息,然后把这些消息在自己本地磁盘存储。

本质上RocketMQ存储海量消息的机制就是分布式存储。

高可用

broker基于主从架构以及多副本策略来保证高可用。

broker是由Master和Slave两种角色的,Master收到消息后会同步给Slave,这样Slave上就能有一模一样的一份副本数据。

这样同一条消息在RocketMQ的整个集群里就有两个副本了,这个时候如果任何一个Master发生故障,还有一个Slave上有一份副本数据,可以保证数据不丢失,继续对外提供服务。

保证了MQ的可靠性可高可用性。

数据路由

对于系统来说,要发送消息到MQ里面去,还要从MQ中获取消息来消费,那么怎么知道有哪些broker,怎么知道要连接到哪一台broker上发送和消费消息?

RocketMQ为了解决这个问题,有一个NameServer的概念,他是独立部署在几台机器上的,然后所有的机器都会把自己注册到NameServer上去,NameServer就知道集群里有哪些broker了。

对于我们的系统而言如果他要发送消息到broker,会去NameServer去获取路由信息,如果系统要从broker获取消息,也会找NameServer获取路由消息,去找对应的broker信息。