消息队列|Kafka消息丢失

2025/4/14 后端消息队列

# 消息丢失

和消息丢失相对应的概念叫可靠消息。在实践中,消息丢失很难定位。

从生产者到消费者到完成消费,每一个环节需要考虑,才能确保自己的消息不会丢失。

# kafka主从同步与ISR

# 写入语义

acks:0、1、2

  • 0:发送即不管
  • 1:主分区写入成功,已经发送成功
  • 2:写入了主分区,还同步所有ISR成员

# ISR

In-Sync Replicas

和leader同步程度一致的follower加入ISR

# 消息丢失的各种场景

# 生产者发送

acks为0,发送消息,生产者能够拿到消息客户端发送的成功响应,但可能broker根本没有拿到;或者处理新消息出现bug了。

但也不是主分区写入就一定没问题了~

# 主从同步

acks为1时。写入主分区,但是主分区所在的broker直接崩溃了。重新选举主分区,不管哪个从分区被选上,都缺了这条消息。

但是asks为all也不是万无一失。

# 刷盘

kafka要么定量刷,要么定时刷。

但kafka强调依赖于副本来保证数据不丢失。

# 消费者提交

消费者提交指消费者提交了偏移量,但是最终没有消费的情况。

仅仅是拿到消息就直接提交,再转交给工作线程。这过程,消费者宕机都会将一个没有消费的消息提交了,这种也叫做消息丢失。

# 面试准备

# 基本思路

# 发送方一定发了消息

类似场景可以抽象成执行业务操作和发送消息这两个步骤。

业务角度上,两个步骤要么都执行,要么都不执行。

  • 本地消息表
  • 消息回查

异步补发机制,可以理解为一个线程定时扫描数据库,找到需要发送但是没有发送出去的消息。

  1. 如果已经提交事务,服务器宕机也没关系,异步补发机制会找出这条消息,进行步伐
  2. 如果消息发成功了,但是数据库没更新,也没关系,还会再发一次,业务方进行幂等
  3. 如果重试机制过程,数据库没更新,也会再发一遍

解决方案就是分布式事务转变成本地事务+补偿机制。

# 消息队列不丢失

acks、禁用unclean选举、刷盘

如果真丢失了消息,只能人手工步伐

# 消息者肯定消费

如果使用了异步消费机制,使用批量消费和批量提交来保证异步消费。

# 在kafka支持消息回查机制

事务消息,两阶段提交。

消息回查机制依赖于消息队列的支持。rocketMQ支持,kafka和rabbitMQ不支持。

给kafka设计一个系统来支持回查功能。 它的基本步骤是这样的:

  1. 应用代码把准备消息发送到topic=look_back_msg上。里面包含业务topic、消息体、业务类型、业务ID、准备状态、回查接口。
  2. 回查中间件消费这个look_back_msg,把消息内容存储到数据库里。
  3. 应用代码执行完业务操作之后,再发送一个消息到look_back_msg上,带上业务类型、业务ID和提交状态这些信息。如果应用代码执行业务出错了,那么就使用回滚状态。
  4. 回查中间件查询消息内容,转发到业务topic上。

# 回查实现

如果业务操作完成之后,没有发提交消息,这时候需要回查中间件来回查。一般来说,回查中间件会异步扫描长时间未提交的消息,然后回查业务方。

回查中间件得知道怎么回查应用代码。要设计成可扩展的,可以回查http接口,也可以回查rpc接口。

# 数据存储

分区表、交替表、分库分表存储延迟消息。同样的,也可以存储回查消息。

# 有序消息

消息回查是要求准备消息和提交消息是有序的。

也就是说,同一个业务的准备消息一定要先于提交消息。解决方案也很简单,在发送的时候要求业务方按照业务ID计算一个哈希值,然后除以分区数量的余数,就是目标分区。

将话题引导导有序消息上。

# 面试思路总结

增强kafka的功能框架,是否能够融合在一起,做成一个开源框架~

Last Updated: 2025/4/14 16:50:39