消息不丢失:生产者收到写入成功响应后消息一定不会丢失吗?
理解消息丢失,需要对生产者到消费者整个环节都有深刻的理解
Kafka主从同步与ISR
- kafka中消息被存在分区中。为了避免分区所在的服务器宕机,分区也是主从结构的。不同的分区之间是一个对等的结构,每一个分区其实是由一个主分区和若干个从分区组成的
- 主从分区都放在broker上,但是在放某个topic分区时,尽量做到一个broker上只放一个主分区,但是可以放别的主分区的从分区
- 避免broker崩溃影响多个主分区
写入语义
写入消息时,既可以是写入主分区,也可以是写入主分区后再写入一部分从分区
- kafka就比较灵活,使用了acks来控制
- acks=0:发送后就不管了,也就是说broker是否收到,收到后是否持久化,是否主从同步,全都不管
- acks=1:当主分区写入成功时,就认为发送成功
- acks=all:不仅写入了主分区,还同步给了所有ISR成员
ISR
- ISR指和主分区保持主从同步的所有从分区。
- 可以通过配置min.insync.replicas配置。比如这个这个值为2时,就说明ISR中至少2个从分区,如果分区数不足,acks=all时,发送消息会失败
消息丢失的场景
生产者发送
- acks=0时,可能broker没有收到消息,或者处理消息时出现了bug
- 启用批量发送功能时,批次较大可能导致kafka连请求都没有发送出去,服务崩溃,也会丢失
主从同步
- acks=1时,只要求写入主分区。假设在写入主分区后,主分区的broker立刻崩溃。这个时候就会重新选举新的主分区,不管哪个分区被选上都缺少这条消息
- acks=all时,kafka还有一种unclean选举。在允许unclean选举时,如果ISR没有任何分区,就会选择第一个分区作为主分区。但是新选出来的主分区可能缺少部分数据
生产者发送和主从同步解决方案
- 设置acks=all,并禁用unclean选举
- 但是这并不是万无一失的,还要考虑刷盘
刷盘
kafka刷盘,要么是定时刷 ,要么是定量刷
kafka控制刷盘的参数有三个
- log.flush.interval.messages:消息到了多少条强制刷新磁盘
- log.flush.interval.ms:间隔多少秒就刷新数据到磁盘
- log.flush.scheduler.interval.ms:间隔多少秒就检查数据是否有需要刷新到磁盘
消费者提交
消费者提交指消费者提交了偏移量,但却没有消费的情况。
- 比如,线程池形态的异步消费,消费者线程拿到消息就直接提交,然后再转交给工作线程。在转交前,或者工作线程处理时,消费者宕机。导致一个未被消费的消息被提交了
解决方案
发送方一定发送了消息
- 可以采用本地消息表或消息回查
本地消息表
- 在发送方,采用本地消息表解决方案。在业务操作过程中,在本地消息表里记录一天代发消息,做成本地数据库事务。然后尝试立刻发送消息,如果成功就把本地消息表里对应数据删除或标记已发送。
- 如果失败就立即重试。同时还有一个异步补发机制,扫描本地消息表,找出长时间没有发送成功的消息。比如三分钟没有发送成功,扫描到后补发
消息队列不丢失
- 把acks设置成all并禁用unclean选举,确保消息发送到消息队列,且不丢失。同时刷盘的三个参数设置成10000,2000,3000。
- 理论上说可能还是会丢失一点消息,但是概率很低。只有一种可能,就是消息队列完成主从同步后,主分区和ISR的从分区没来得及刷盘就挂了,才会导致消息丢失,此时消息是真的丢失了,只能人工补发
消费者肯定消费
- 确保消费者肯定消费,大多数时候不需要做什么操作,但是如果使用了异步消费机制就需要考虑了
- 如A业务采用异步消费提高消费速率,只要利用批量消费、批量提交保证异步消费,也不会出现未消费问题
亮点方案:在kafka上支持消息回查机制
消息回查指消息队列允许在发送消息的时候,先发一个准备请求,里面带着消息。这个时候消息队列并不会把消息传给消费者,而是业务完成后,需要再发一个确认请求,这个时候中间件才会把消息转交给消费者
-
kafka不支持回查机制。可以自己设计一个回查功能的系统
-
1.业务代码把准备消息发送到topic=look_back_msg上
- 里面包含业务topic、消息体、业务类型、业务ID、准备状态、回查接口
-
2.回查中间件把准备消息存储到数据库
-
3.业务代码执行完操作后,再发一个消息到look_back_msg上
- 带上业务类型、业务ID和提交状态,如果应用代码执行错误,那么就使用回滚状态
-
4.回查中间件查询消息内容,转发到业务topic上
亮点一:回查实现
-
回查中间件要知道怎么回查应用代码
- 回查机制要设计成可扩展的,可以回查HTTp接口,也可以回查RPC接口
-
HTTP
- POST方法
- Body带上业务类型和业务ID
- 业务方提供回查URL
-
RPC:一般使用泛用化调用
亮点二:数据存储
- 为了保证会查机制的高性能和高可靠,使用了分区表。按照时间分区,并且历史分区是可以快速归档的,因为回查机制的数据库只是临时存储一下消息数据。考虑后续业务拓展。也可以按照业务topic来分库分表
亮点三:有序消息
-
同一个业务的准备消息一定先于提交消息
- 可以在发送时要求业务方按照业务ID计算一个哈希值,然后除以分区数量的余数就是目标分区。从而实现有序消息