书接上文继续聊聊MQ的问题吧。想要了解MQ之前的问题可阅读:
面试官:继上次聊的MQ的问题,想再问问有了解过MQ如何保证其高可用性吗?这个可以简单聊聊吗
派大星:当然可以。
Rabbit MQ有三种模式:单机模式
-(demo级别的,生产很少使用,这里就无需再说啦)、普通集群模式
以及镜像集群模式
普通集群模式
:它是非分布式非高可用
。意思就是在多个机器上启动多个Rabbit MQ实例,每个机器启动一个,但是你创建的queue只会放在一个Rabbit MQ实例上,但是每个实例都去同步queue的元数据。这样在你消费的时候实际上如果连接到了另外一个实例,那么这个实例会去queue所在的实例上将数据拉取过来。这种方式很麻烦并且没有做到所谓的分布式,就是普通的集群。这样会导致要么消费者每次随机连接一个实例然后拉取数据,要么就固定连接那个queue的实例消费数据,前者有数据拉取的开销,后者导致单实例的瓶颈。它的优点是这种模式只是提高了消费者消费的吞吐量。缺点也显而易见:其一就是可能会在Rabbit MQ集群内部产生大量的数据传输,再者就是可用性没有什么保障,如果queue所在的节点宕机了,数据就丢失了,因为那个queue所在的实例包含元数据和实际数据。
镜像集群模式
简单如图所示:这种模式才是所谓的Rabbit MQ真正的高可用模式,与普通集群模式不同的是:你创建的queue无论是元数据还是queue的消息会存在于多个实例上,每次写消息到queue的时候,都会自动把消息与多个实例的queue进行消息同步。它的优点就是其中某个机器宕机了,别的机器还可以继续提供服务。缺点:这个性能相比较而言开销较大,消息需要同步所有消息。导致网络带宽压力和消耗很重。还有一点就是所谓的扩展性几乎没有,因为假设某个queue的数据负载很重,加机器无法线性去扩展queue。
面试官:嗯,不错。那你知道如何开启Rabbit MQ的镜像模式吗?
派大星:其实就是在管理控制台新增一个镜像集群的策略,要求所有节点同步数据。
面试官:嗯,可以。那你知道Kafka的高可用性如何保证吗?
派大星:首先我们要有个基本的认识,简单如图所示:
我们都知道Kafka是多个broker组成,每个broker是一个节点,你创建一个topic,这个topic可以划分为多个partition,每个partition可以存在不同的broker上,每个partition就放一部分数据。天然的分布式消息队列。因为一个topic数据是分散在多个机器上的。每个机器只存放一部分数据
。
Tip:
Kafka0.8之前是没有HA(高可用)机制的。就是任何一个broker宕机了,那么这个broker上的partition就废了,没法写也没有办法读。Kafka0.8以后,提供了HA机制,就是replica副本机制,每个partition的数据都会同步到其它机器上,形成自己的多个replica副本。然后所有replica会选举出一个leader出来,那么生产和消费都和这个leader打交道,然后其它的replica就是follower。写的时候leader只负责把数据同步到follwer上,读的时候直接读leader。如果leader宕机follwer会变成leader,follwer变成leader过程无法提供对外服务。
面试官:很好,那在生产环境中如何保证消息不被重复消费呢?或者说如何保证消息的幂等性。
派大星:首先针对于Kafka来说,出现这种情况的原因是:消费者offset没来得及提交导致重复消费。大致可参考下图:
面试官:那你能说说针对幂等性问题有什么解决方案吗?
派大星:方案需要根据不同的场景做不同的应对。情况一:如何生产者不重复发送消息到MQ。可以通过让mq内部可以为每条消息生成一个全局唯一、与业务无关的消息id,当mq接收到消息时,会先根据该id判断消息是否重复发送,mq再决定是否接收该消息。情况二:如何保证消费者不重复消费。其重点在于如何让消费者保证不重复消费的关键在于消费者端做控制,因为MQ不能保证不重复发送消息,所以应该在消费者端控制:即使MQ重复发送了消息,消费者拿到了消息之后,要判断是否已经消费过,如果已经消费,直接丢弃。所以根据实际业务情况,有下面几种方式:
面试官:不错。可不可以再聊聊不同MQ如何保证消息传输的可靠性呢?或者说如何处理消息丢失的问题。
派大星:额... .要不下次说吧。这次有点累啦。