Rocketmq如何保证消息不丢失和幂等性

生产者

生产者通过RocketMQ提供的事务消息(两阶段提交)能保证消息的一致性。
第一阶段给Broker发送一个半事务消息,半事务消息是不能消费的消息,broker已经收到生产者发送的消息,但是并未收到生产者的二次确认,所以该消息被标记为【暂不能投递】状态(即消费者不能消费这条消息);
如果Producer发送成功,则执行本地事务,如果本地事务执行成功则二次确认消息,向Broker发送commit消息,如果本地事务执行失败则发送Rollback消息给Broker。如果Producer发送半事务消息后没有收到Broker的成功响应,可能是因为网络抖动,Broker宕机(则触发重试机制,在重试后仍然失败则将该消息持久化,通过线程扫描定时发送到Broker,直到Broker恢复)。
如果由于网络抖动,生产者重启导致而消息确认失败,Broker会通过扫描发现某条消息长期处于【半事务消息】状态,就会主动向生产者发起询问查询该条消息的最终状态,默认每隔60s回查一次,回查15次还是不行,则不投递半事务消息。

Ro
事务消息发送步骤如下:

  1. 生产者将半事务消息发送至 RocketMQ Broker。
  2. RocketMQ Broker 将消息持久化成功之后,向生产者返回 Ack 确认消息已经发送成功,此时消息暂不能投递,为半事务消息。
  3. 生产者开始执行本地事务逻辑。
  4. 生产者根据本地事务执行结果向服务端提交二次确认结果(Commit或是Rollback),服务端收到确认结果后处理逻辑如下:
  • 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者。
  • 二次确认结果为Rollback:服务端将回滚事务,不会将半事务消息投递给消费者。
  1. 断网或者是生产者应用重启的特殊情况下,若服务端未收到发送者提交的二次确认结果,或服务端收到的二次确认结果为Unknown未知状态,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查。
  2. 需要注意的是,服务端仅仅会按照参数尝试指定次数,超过次数后事务会强制回滚,因此未决事务的回查时效性非常关键,需要按照业务的实际风险来设置

消费者

消费者保证不丢失和幂等性

消息幂等判断去重

消费者消费到消息后,如何保证消息的幂等,很容易想到的是通过if判断;比如用户下单,在用户支付订单后,更新订单状态同时发布一条消息到Broker,通知下游服务新增物流、更新用户积分等信息,我们就那新增物流信息为例,物流服务在消费该消息时,通过if判断物流信息表中是否存在相同的物流id,不存在则正常消费,存在则直接return,不重复消费。

if(null != xxxMapper.selectById(id)) {return "success";
}
// todo 消费逻辑
问题分析

该方案非常简单,但是在大量并发和复杂的网络环境下,如果细节没有处理好会有很多漏洞。

  • 并发情况下如果网络抖动导致消息重复消费,在第一条消息没有消费完成,重复的消息又执行这个if判断会导致主键冲突异常
  • 在业务层面重复消费可能导致库存扣减两倍,用户积分也会新增两倍。
锁机制+事务去重
  • 在新增信息的表中,做好主键冲突的异常捕获处理
  • 将xxxMapper.selectById(id)的select语句使用for update和消费逻辑使用事务处理。
    这样虽然能保证消息不会重复消费,但是牺牲了很大的性能开销,因为消费消息逻辑被整个事务包裹而导致处理时间被延长。并且还增加了整个系统的复杂度,因为还有其他业务需要消费消息,其实我们还可以继续思考,引入所有业务更加通用的方案。
本地事务消息表

引入一张非业务的消息表,记录消息消费的状态,状态包括两种:消费中/已消费。将它与其他业务绑定在一起作为一个本地事务,大致逻辑如下:

  • 开启事务
  • 插入消息表
  • 处理其他业务(比如:新增物流,更新积分,更新库存信息)
  • 提交/回滚事务

虽然他没有对数据库记录加锁,但是他还是使用事务,有事务就会延长消费时间

去事务的本地消息表解决方案

利用消息表的消息状态作为基础条件,

  • 消费者消费首先插入消息去重表,
  • 插入成功,则继续执行消费逻辑:
    • 消费失败,则删除消息表,延迟继续消费
    • 消费成功,则更新消息表消息状态为已消费
  • 插入失败分为两种情况:
    • 消息如果在消费中,则延迟继续消费;
    • 消息如果已经消费,返回消费成功

特别注意:延迟继续消费的消息需要判断消费时长,或者消费次数,达到消费上限则告警,或者投递到死信Topic中。

代码和方案持续优化更新中。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/685802.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot+Vue+Java的校园资料分享平台

💞 文末获取源码联系 🙉 👇🏻 精选专栏推荐收藏订阅 👇🏻 🎀《Java 精选实战项目-计算机毕业设计题目推荐-期末大作业》😘 更多实战项目~ https://www.yuque.com/liuyixin-rotwn/ei3…

JavaScript使用 BigInt

在 JavaScript 中,最大的安全整数是 2 的 53 次方减 1,即 Number.MAX_SAFE_INTEGER,其值为 9007199254740991。这是因为 JavaScript 中使用双精度浮点数表示数字,双精度浮点数的符号位占 1 位,指数位占 11 位&#xff…

2024洗地机选购指南 | 怎么选洗地机不会被坑?

家里的地板总是需要打扫,但工作忙碌的我们往往没有足够的时间来打理。洗地机不仅能够帮助我们节省宝贵的时间,还能让我们的家变得一尘不染。今天,笔者将为大家讲讲挑选洗地机的技巧,告诉大家怎么挑选洗地机不会被坑,顺…

ArrayList底层结构和源码分析

ArrayList的注意事项 1,permits all, including null, ArrayList 甚至可以加入多个null,并且可放多个 2,ArrayList 是由数组来实现数据存储的 3,ArrayList 基本等同于Vector,除了ArrayList 是线程不安全但执行效率高…

ICode国际青少年编程竞赛- Python-4级训练场-while语句入门

ICode国际青少年编程竞赛- Python-4级训练场-while语句入门 1、 while Flyer.disappear():wait() Dev.step(2)2、 Dev.step(1) while Flyer.disappear():wait() Dev.step(5)3、 while Flyer[0].disappear():wait() Dev.step(3) Dev.step(-1) while Flyer[0].disappear():…

通用产品发布解决方案(家居分类表设计以及renren代码生成器的使用)

文章目录 1.商品分类表设计1.需求分析2.数据库表设计1.数据库sunliving_commodity,商品分类表commodity_category2.测试数据 2.代码生成器生成crud1.解压到sunliving下并聚合管理1.解压2.修改sunliving的pom.xml进行聚合管理3.刷新maven报错 parent.relativePath4.将…

cookie,session,token

目的:解决用户登录状态 从一个简单的登录开始说起, 在我们访问bilibili的时候,第一次需要登录,但后续就不需要登录了,可以直接访问bilibili。 而且每次在页面请求服务器的资源都需要维持登录状态,如果没…

10000字讲解IoC 思想以及五大注解

文章目录 IoC 思想通过案例讲解 IoC1.传统的开发方式 SpringIoC 和 DI五大注解ControllerServiceComponentRepositoryConfiguration 为什么要有这么多的类注解类注解之间的关系方法注解 Bean重命名 bean扫描路径 IoC 思想 什么是 Spring 呢? 我们经常听到的都是说…

【SAP ME 38】SAP ME发布WebService配置及应用

更多WebService介绍请参照 【SAP ME 28】SAP ME创建开发组件(DC)webService 致此一个WebService应用发布成功,把wsdl文件提供到第三方系统调用接口! 注意: 在SAP ME官方开发中默认对外开放的接口是WebService接口&am…

springboot3项目练习详细步骤(第二部分:文章分类模块)

新增文章分类 接口文档 业务实现 参数校验 文章分类列表 接口文档 业务实现 获取文章分类详情 接口文档 业务实现 更新文章分类 接口文档 业务实现 分组校验 问题 概念 实现步骤 总结 删除文章分类 接口文档 业务实现 该模块大部分请求的路径相同&…

LeetCode 209 长度最小的子数组(滑动窗口and暴力)

、 法一:滑动窗口 //使用滑动窗口来解决问题 //滑动窗口的核心点有: /*1.窗口内是什么?2.如何移动窗口的起始位置?3.如何移动窗口的结束位置?4.两个指针,怎么判断哪个指针是终止指针,哪个指针…

智慧无人店运营再添黑马,萤石云值守服务显身手

许多创业者选择开店,是出于对自由生活的向往。然而,现实总会给人重重一击。老板们常常面临着熬夜看店、全年无休的困境,而选择增加雇佣员工看店又会面临着成本高昂、利润微薄的问题。“开店容易守店难”、“没有自由”成为了许多店主的共同心…