消息队列|Kafka消息丢失
# 消息丢失
和消息丢失相对应的概念叫可靠消息。在实践中,消息丢失很难定位。
从生产者到消费者到完成消费,每一个环节需要考虑,才能确保自己的消息不会丢失。
# 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强调依赖于副本来保证数据不丢失。
# 消费者提交
消费者提交指消费者提交了偏移量,但是最终没有消费的情况。
仅仅是拿到消息就直接提交,再转交给工作线程。这过程,消费者宕机都会将一个没有消费的消息提交了,这种也叫做消息丢失。
# 面试准备
# 基本思路
# 发送方一定发了消息
类似场景可以抽象成执行业务操作和发送消息这两个步骤。
业务角度上,两个步骤要么都执行,要么都不执行。
- 本地消息表
- 消息回查
异步补发机制,可以理解为一个线程定时扫描数据库,找到需要发送但是没有发送出去的消息。
- 如果已经提交事务,服务器宕机也没关系,异步补发机制会找出这条消息,进行步伐
- 如果消息发成功了,但是数据库没更新,也没关系,还会再发一次,业务方进行幂等
- 如果重试机制过程,数据库没更新,也会再发一遍
解决方案就是分布式事务转变成本地事务+补偿机制。
# 消息队列不丢失
acks、禁用unclean选举、刷盘
如果真丢失了消息,只能人手工步伐
# 消息者肯定消费
如果使用了异步消费机制,使用批量消费和批量提交来保证异步消费。
# 在kafka支持消息回查机制
事务消息,两阶段提交。
消息回查机制依赖于消息队列的支持。rocketMQ支持,kafka和rabbitMQ不支持。
给kafka设计一个系统来支持回查功能。 它的基本步骤是这样的:
- 应用代码把准备消息发送到topic=look_back_msg上。里面包含业务topic、消息体、业务类型、业务ID、准备状态、回查接口。
- 回查中间件消费这个look_back_msg,把消息内容存储到数据库里。
- 应用代码执行完业务操作之后,再发送一个消息到look_back_msg上,带上业务类型、业务ID和提交状态这些信息。如果应用代码执行业务出错了,那么就使用回滚状态。
- 回查中间件查询消息内容,转发到业务topic上。
# 回查实现
如果业务操作完成之后,没有发提交消息,这时候需要回查中间件来回查。一般来说,回查中间件会异步扫描长时间未提交的消息,然后回查业务方。
回查中间件得知道怎么回查应用代码。要设计成可扩展的,可以回查http接口,也可以回查rpc接口。
# 数据存储
分区表、交替表、分库分表存储延迟消息。同样的,也可以存储回查消息。
# 有序消息
消息回查是要求准备消息和提交消息是有序的。
也就是说,同一个业务的准备消息一定要先于提交消息。解决方案也很简单,在发送的时候要求业务方按照业务ID计算一个哈希值,然后除以分区数量的余数,就是目标分区。
将话题引导导有序消息上。
# 面试思路总结
增强kafka的功能框架,是否能够融合在一起,做成一个开源框架~