消息不丢失:生产者收到写入成功响应后消息一定不会丢失吗?

消息不丢失:生产者收到写入成功响应后消息一定不会丢失吗?

理解消息丢失,需要对生产者到消费者整个环节都有深刻的理解

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控制刷盘的参数有三个

消费者提交

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

  • 比如,线程池形态的异步消费,消费者线程拿到消息就直接提交,然后再转交给工作线程。在转交前,或者工作线程处理时,消费者宕机。导致一个未被消费的消息被提交了

解决方案

发送方一定发送了消息

  • 可以采用本地消息表或消息回查
本地消息表
  • 在发送方,采用本地消息表解决方案。在业务操作过程中,在本地消息表里记录一天代发消息,做成本地数据库事务。然后尝试立刻发送消息,如果成功就把本地消息表里对应数据删除或标记已发送。
  • 如果失败就立即重试。同时还有一个异步补发机制,扫描本地消息表,找出长时间没有发送成功的消息。比如三分钟没有发送成功,扫描到后补发

消息队列不丢失

  • 把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计算一个哈希值,然后除以分区数量的余数就是目标分区。从而实现有序消息
相关推荐
MadPrinter6 分钟前
SpringBoot学习日记 Day11:博客系统核心功能深度开发
java·spring boot·后端·学习·spring·mybatis
dasseinzumtode6 分钟前
nestJS 使用ExcelJS 实现数据的excel导出功能
前端·后端·node.js
淦出一番成就9 分钟前
Java反序列化接收多种格式日期-JsonDeserialize
java·后端
Java中文社群11 分钟前
Hutool被卖半年多了,现状是逆袭还是沉寂?
java·后端
cg.family18 分钟前
Doris 消费kafka消息
kafka·doris
程序员蜗牛44 分钟前
9个Spring Boot参数验证高阶技巧,第8,9个代码量直接减半!
后端
yeyong1 小时前
咨询kimi关于设计日志告警功能,还是有启发的
后端
库森学长1 小时前
2025年,你不能错过Spring AI,那个汲取了LangChain灵感的家伙!
后端·openai·ai编程
Java水解1 小时前
Spring Boot 启动流程详解
spring boot·后端
学历真的很重要1 小时前
Claude Code Windows 原生版安装指南
人工智能·windows·后端·语言模型·面试·go