前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >对线面试官 - MQ经典面试题之高可用性及幂等性

对线面试官 - MQ经典面试题之高可用性及幂等性

作者头像
@派大星
发布2023-09-08 17:17:34
发布2023-09-08 17:17:34
1880
举报
文章被收录于专栏:码上遇见你码上遇见你

书接上文继续聊聊MQ的问题吧。想要了解MQ之前的问题可阅读:

对线面试官-为什么要使用MQ

面试官:继上次聊的MQ的问题,想再问问有了解过MQ如何保证其高可用性吗?这个可以简单聊聊吗

派大星:当然可以。

  1. 首先说一说Rabbit 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拿到数据是要存到数据库,那么可以根据数据创建唯一约束,这样的话,同样的数据从MQ发送过来之后,当插入数据库的时候,会报违反唯一约束,不会插入成功的。(或者可以先查一次,是否在数据库中已经保存了,如果能查到,那就直接丢弃就好了)。
  • 让生产者发送消息时,每条消息加一个全局的唯一id,然后消费时,将该id保存到redis里面。消费时先去redis里面查一下有么有,没有再消费。(其实原理跟第一点差不多)。
  • 如果拿到的数据是直接放到redis的set中的话,那就不用考虑了,因为set集合就是自动有去重的。

面试官:不错。可不可以再聊聊不同MQ如何保证消息传输的可靠性呢?或者说如何处理消息丢失的问题。

派大星:额... .要不下次说吧。这次有点累啦。


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码上遇见你 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档