首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >高并发场景下:如何保证消息只被消费一次

高并发场景下:如何保证消息只被消费一次

作者头像
lyb-geek
发布2026-03-09 16:01:23
发布2026-03-09 16:01:23
1190
举报
文章被收录于专栏:Linyb极客之路Linyb极客之路

1、为什么需要保证消息只被消费一次?

在项目中,如果使用到了消息队列,就会遇到消息丢失的问题,为了解决消息丢失,常常会采用补发消息来解决,这样就会引发消费者多次收到同一条消息,导致业务处理异常,如:订单被支付多次、业务逻辑被重复处理引发系统异常。

2、消息为什么会丢失?

在使用消息队列的过程中,通常有三个场景会导致消息丢失;

场景1:生产者发送消息到消息队列存储的过程中发生消息丢失

在实际场景中,消息生产者一般是业务服务器,它一般独立部署在对应的服务器上,跟消息队列通信一般由网络完成,而网络通信是有可能发生抖动的,消息发送就有可能因为网络的错误而丢失。

解决生产者发送消息到消息队列丢失的问题,业内常常有成熟的解决方案,就以国内常使用的 RocketMQ 来说,它可以开启 ack 确认机制,当生产者发送一个消息给消息队列的时候,消息队列收到了消息,它就会返回一个 ack,生产者收到这个 ack才能够代表这个消息被正确投递到消息队列中,如果没有收到,生产者就需要做重传处理。

场景2:消息队列接收到生产者发送的消息,将消息持久化到硬盘的过程中也可能会出现消息的丢失

该此场景中发生的消息丢失,是与消息队列它的刷盘机制有关系的,如果是异步刷盘,生产者发送消息到消息队列,消息队列接收到消息后,消息不是直接存储到磁盘的,而是会先更新到内存里面又或者是存储在操作系统的缓存里,只有当缓存里面的消息累积到一定的消息数量之后,它才会将这些消息统一刷新到磁盘里面,如果这个时候消息队列发生了重启,在内存里面没来得及刷新到磁盘的消息就会丢失;

解决这个问题可以开启消息队列的同步刷盘机制,开启后,生产者发送消息到消息队列,它立马就会将这个消息刷新到磁盘,但是同步刷盘的方式会使消息队列的性能一点损耗。

另外,除了单节点的消息队列存在消息丢失的问题,集群的消息队列也同样存在消息丢失的问题,而且情况比单节点更加复杂。

在消息队列是集群的情况下,有可能遇到当生产者发送消息给消息队列时,主节点接收到了生产者发送到消息,并且成功将消息写入到磁盘中,但是消息还没来得及同步到子节点,此时主节点发生宕机,子节点被晋升为主节点,遇到这种情况,消息也会发生丢失;

同样也是可以通过开启同步刷盘的机制,使消息在没有被集群中所有节点接收的情况下,如果发生宕机,不会正确返回 ack 给生产者,从而确保消息正确投递,保证消息不丢失。

场景3:消费者拉取到消息队列的消息,但是消费者在消费的过程中出现了宕机,导致消息丢失。

该场景发生的消息丢失,拿 RabbitMQ 来说,可以通过手动 ack 的方式进行解决,消费者拉取到消息队列中的消息,执行对应的处理逻辑,执行完成后再给消息队列发送 basic_ack,失败时通过 basic_nack 重新队。

如果多次重试失败,将失败的消息转入 DLQ(死信队列),避免阻塞主队列。

3、如何保证消息只被消费一次?

前面介绍消息为什么会出现重复,并且介绍了哪些场景会出现消息丢失,接下来就来讲讲应该如何保证消息只被消费一次。

当消费者开始进行消息处理的时候,先往 redis 组件中记录一条带处理状态的缓存记录,再进行业务逻辑处理,如果此时处理逻辑执行成功,没有异常,则更新缓存中的处理状态并返回 ack 处理成功;

假设此时出现重复消息,获取缓存时就会发现已经记录了该消息已经消费的缓存状态,直接返回 ack 处理成功即可,不用重复执行业务逻辑处理,这样就做到了这条消息消费多次和消费一次的结果是一致的。

另外在执行处理逻辑的时候,也有可能发生宕机或重启,在处理中的消息就没有办法正常更新缓存的状态,导致延迟消息一直重发,陷入死循环;

像遇到这种情况,可以借助 redis 的缓存过期时间来解决,在记录缓存的步骤,可以将缓存设置为 1 分钟过期,在正常的情况下,业务逻辑执行成功,再将缓存过期时间修改为永久;如果执行业务逻辑时发生异常,因为没有将缓存过期时间修改为永久,缓存记录过 1 分钟就会失效,延迟消息重试时就不会一直陷入死循环。

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

本文分享自 Linyb极客之路 微信公众号,前往查看

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

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

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