如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

秃头哥
• 阅读 179

面试题

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

面试官心理分析

其实这是很常见的一个问题,这俩问题基本可以连起来问。既然是消费消息,那肯定要考虑会不会重复消费?能不能避免重复消费?或者重复消费了也别造成系统异常可以吗?这个是 MQ 领域的基本问题,其实本质上还是问你使用消息队列如何保证幂等性,这个是你架构里要考虑的一个问题。

面试题剖析

回答这个问题,首先你别听到重复消息这个事儿,就一无所知吧,你先大概说一说可能会有哪些重复消费的问题

首先,比如 RabbitMQ、RocketMQ、Kafka,都有可能会出现消息重复消费的问题,正常。因为这问题通常不是 MQ 自己保证的,是由我们开发来保证的。挑一个 Kafka 来举个例子,说说怎么重复消费吧。

Kafka 实际上有个 offset 的概念,就是每个消息写进去,都有一个 offset,代表消息的序号,然后 consumer 消费了数据之后,每隔一段时间(定时定期),会把自己消费过的消息的 offset 提交一下,表示“我已经消费过了,下次我要是重启啥的,你就让我继续从上次消费到的 offset 来继续消费吧”。

但是凡事总有意外,比如我们之前生产经常遇到的,就是你有时候重启系统,看你怎么重启了,如果碰到点着急的,直接 kill 进程了,再重启。这会导致 consumer 有些消息处理了,但是没来得及提交 offset,尴尬了。重启之后,少数消息会再次消费一次。

举个例子。

有这么个场景。数据 1/2/3 依次进入 kafka,kafka 会给这三条数据每条分配一个 offset,代表这条数据的序号,我们就假设分配的 offset 依次是 152/153/154。消费者从 kafka 去消费的时候,也是按照这个顺序去消费。假如当消费者消费了 offset=153 的这条数据,刚准备去提交 offset 到 zookeeper,此时消费者进程被重启了。那么此时消费过的数据 1/2 的 offset 并没有提交,kafka 也就不知道你已经消费了 offset=153 这条数据。那么重启之后,消费者会找 kafka 说,嘿,哥儿们,你给我接着把上次我消费到的那个地方后面的数据继续给我传递过来。由于之前的 offset 没有提交成功,那么数据 1/2 会再次传过来,如果此时消费者没有去重的话,那么就会导致重复消费。

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

如果消费者干的事儿是拿一条数据就往数据库里写一条,会导致说,你可能就把数据 1/2 在数据库里插入了 2 次,那么数据就错啦。

其实重复消费不可怕,可怕的是你没考虑到重复消费之后,怎么保证幂等性

举个例子吧。假设你有个系统,消费一条消息就往数据库里插入一条数据,要是你一个消息重复两次,你不就插入了两条,这数据不就错了?但是你要是消费到第二次的时候,自己判断一下是否已经消费过了,若是就直接扔了,这样不就保留了一条数据,从而保证了数据的正确性。

一条数据重复出现两次,数据库里就只有一条数据,这就保证了系统的幂等性。

幂等性,通俗点说,就一个数据,或者一个请求,给你重复来多次,你得确保对应的数据是不会改变的,不能出错

所以第二个问题来了,怎么保证消息队列消费的幂等性?

其实还是得结合业务来思考,我这里给几个思路:

  • 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。
  • 比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。
  • 比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
  • 比如基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

当然,如何保证 MQ 的消费是幂等性的,需要结合具体的业务来看。


针对于上面所涉及到的知识点我总结出了有1到5年开发经验的程序员在面试中涉及到的绝大部分架构面试题及答案做成了文档和架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习,也可以关注我一下以后会有更多干货分享。

资料获取方式: QQ群搜索“708-701-457” 即可免费领取

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?
如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?
如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

点赞
收藏
评论区
推荐文章
peter peter
4年前
Go:分布式锁实现原理与最佳实践
分布式锁应用场景很多应用场景是需要系统保证幂等性的(如api服务或消息消费者),并发情况下或消息重复很容易造成系统重入,那么分布式锁是保障幂等的一个重要手段。另一方面,很多抢单场景或者叫交易撮合场景,如dd司机抢单或唯一商品抢拍等都需要用一把“全局锁”来解决并发造成的问题。在防止并发情况下造成库存超卖的场景,也常用分布式锁来解决。实现
Centos7安装RabbitMQ详细教程 - 附带软件基本解释 - CSDN博客
MQ引言什么是MQMQ:messageQueue翻译为消息队列,通过典型的生产者和消费者模型不断向消息队列中生产消息,消费者不断从队列中获取消息。因为消息的生产和消费都是一部的,而且只关心消息的发送和接收,没有业务逻辑的侵入,轻松的实现了系统之间的解耦。别名是消息中间件,通过利用高效的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系
Stella981 Stella981
3年前
Kafka设计
1.幂等消息为了解决重试导致的消息重复、乱序问题,kafka引入了幂等消息。幂等消息保证producer在一次会话内写入一个partition内的消息具有幂等性,可以通过重试来确保消息发布的ExactlyOnce语义。实现逻辑很简单:区分producer会话producer每次启动后,首先向broker申请一
Stella981 Stella981
3年前
RabbitMq学习笔记——概念
1、RabbitMQ简介  MQ全称为MessageQueue(消息队列),是一种“应用程序”<—“应用程序”的通信方法。MQ是一个典型的“消费”<—“生产者”模型的代表,生成者往消息队列中写入消息,消费者从消息队列中读取消息。2、MQ的应用场景  对于一个大型的软件系统来说,它会有很多的组件或者说模块或者说子系统或者
Stella981 Stella981
3年前
RabbitMQ如何保证队列里的消息99.99%被消费?
1\.本篇概要其实,还有1种场景需要考虑:当消费者接收到消息后,还没处理完业务逻辑,消费者挂掉了,那消息也算丢失了?,比如用户下单,订单中心发送了1个消息到RabbitMQ里的队列,积分中心收到这个消息,准备给这个下单的用户增加20积分,但积分还没增加成功呢,积分中心自己挂掉了,导致数据出现问题。那么如何解
Stella981 Stella981
3年前
Kafka在哪些场景下会造成重复消费或消息丢失?
kafka消费者在消费的时候对于位移提交的具体时机的把握也很有讲究,有可能会造成重复消费和消息丢失的现象。!(https://oscimg.oschina.net/oscnet/3566bbd82538478396a25dd6e023974e.png"image.png")参考上图,当前一次poll()操作所拉取的消
Wesley13 Wesley13
3年前
mq要如何处理消息丢失、重复消费?
如果要你实现一个支付宝向余额宝转账的功能,比如:账户a从支付宝转出5000余额宝转入5000,该怎么做呢?可能有些人会说,这还不简单,直接上图!(https://oscimg.oschina.net/oscnet/7d47d132357446109035157b25361ec7.png)支付宝先给账户a减5000,调用余额
Wesley13 Wesley13
3年前
JMS消息的概念解释
1、默认生产者消息是持久的:会存数据库\消费者的持久:createDurableSubscriber是指消费者能收到所有它订阅时间点之后的消息,即使消费者注册后关闭,当它重启就能收到注册时间点之后所有的消息;即当此消费用户ID(AAA)在producer发送之前就已经注册,那么此id能收到producer发送的所有消息,如果是在produce
Stella981 Stella981
3年前
RabbitMq学习(二)RabbitMQ的消息确认机制
一.为什么有消息确认机制在RabbitMq中,一个消息从产生到最终的消息接受,中间大致会有三个环节,首先是消息到达交换机、然后是消息通过交换机到达队列,最后消费者消费绑定的队列消息。 但是在这个过程中,如果出现网络或者系统的异常,就会导致消息不能被正常消费。如果不能正常消费消息,会造成两方面的问题。 1.1在服务端消息到
Wesley13 Wesley13
3年前
MQ 消息队列
1、场景作用削峰填谷,异步解耦。2、如何保证消息不被重复消费呢?这个问题可以换个思路,保证消息重复消费,其实是保证程序的幂等性。无论消息如何重复,程序运行的结果是一致的。比如消费消息后做数据库插入操作,为了防止消息重复消费,可以在插入前先查询一下有没有对应的数据。3、怎么保证从消息队列里拿到的数据按顺序执
融云IM即时通讯 融云IM即时通讯
7个月前
融云IM干货丨IM聊天室中客户端如何确保消息同步的准确性?
客户端确保消息同步的准确性主要依赖于以下几个关键技术和策略:全局唯一的消息ID生成策略:为了保证消息可以通过ID进行识别和排重,IM系统采用全局唯一的消息ID生成策略。这种策略可以确保每条消息都有一个唯一的标识符,从而在消息的发送和接收过程中避免重复。客户
秃头哥
秃头哥
Lv1
人越长大就越不愿意把心事向身边的人吐露.
文章
4
粉丝
0
获赞
0