如何保证消息一定被消费

为什么消息会丢失?(三个消息可能丢失的地方)

1、消息在写到消息队列的过程中丢失

业务服务器和消息队列服务器可能会出现网络抖动,当出现了网络抖动,消息就会丢失。

1)消息生产者把消息发送给MQ,如果接收成功,MQ会返回一个ack消息给生产者

2)如果消息接收不成功,MQ会返回一个nack消息给生产者

发送方在消息发送到MQ之后,将消息给写到硬盘上,这样即使MQ服务器宕机,也不会导致未消费的消息丢失.

当高并发场景下这种方式显而易见是不合理的,因为与磁盘进行I/O交互是相对非常慢的.当然这种情况我们可以有解决方案: 可以在缓存中将消息缓存下来,比如当消息满1000条时就将这些消息一次性写到磁盘中.

这种方案虽然可以解决I/O交互问题.但是还是不能解决宕机出现的问题,假如缓存了900条消息,并且这些消息均为被消费,此时宕机了,同样会导致消息的丢失.显然这种解决方案还需要优化.

加上一个补偿机制,只要缓存redis中的消息还是发送中的状态,定时任务启动时就要重新发送

定时任务那边加上一个补偿的次数,一般不超过3次

不过这样的方案,就会有可能发送多次相同的消息,那就要要求消费者一定在消费的时候保障幂等性

2、 消息在消息队列中丢失( Kafka 为例)

消息在Kafka 中是存储在本地磁盘上的, 为了减少消息存储对磁盘的随机 I/O,一般我们会将消息写入到操作系统的 Page Cache 中,然后在合适的时间将消息刷新到磁盘上。

例如,Kafka 可以配置当达到某一时间间隔,或者累积一定的消息数量的时候再刷盘,也就是所谓的异步刷盘。

如果发生机器掉电或者机器异常重启,那么 Page Cache 中还没有来得及刷盘的消息就会丢失了,如果把刷盘的间隔设置很短,或者设置累积一条消息就就刷盘,这样频繁刷盘会对性能有比较大的影响

如果系统对消息丢失的容忍度很低,那么可以考虑以集群方式部署 Kafka 服务

集群方式部署 Kafka 服务

Kafka 集群中有一个 Leader 负责消息的写入和消费,可以有多个 Follower 负责数据的备份。Follower 中有一个特殊的集合叫做 ISR(in-sync replicas),当 Leader 故障时,新选举出来的 Leader 会从 ISR 中选择,默认 Leader 的数据会异步地复制给 Follower,这样在 Leader 发生掉电或者宕机时,Kafka 会从 Follower 中消费消息,减少消息丢失的可能。

由于默认消息是异步地从 Leader 复制到 Follower 的,所以一旦 Leader 宕机,那些还没有来得及复制到 Follower 的消息还是会丢失

为了解决这个问题,Kafka 为生产者提供一个选项叫做“acks”,当这个选项被设置为“all”时,生产者发送的每一条消息除了发给 Leader 外还会发给所有的 ISR,并且必须得到 Leader 和所有 ISR 的确认后才被认为发送成功。这样,只有 Leader 和所有的 ISR 都挂了,消息才会丢失。

总结
  1. 如果你需要确保消息一条都不能丢失,那么建议不要开启消息队列的同步刷盘,而是需要使用集群的方式来解决,可以配置当所有 ISR Follower 都接收到消息才返回成功。

  2. 如果对消息的丢失有一定的容忍度,那么建议不部署集群,即使以集群方式部署,也建议配置只发送给一个 Follower 就可以返回成功了。

3、在消费的过程中存在消息丢失的可能

消费的过程分为三步:接收消息、处理消息、更新消费进度

一定要等到消息接收和处理完成后才能更新消费进度,不过这就会造成消息重复的问题,那么消费者就要做好幂等处理

posted @   上好佳28  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示