RocketMQ —消费重试

消费者出现异常,消费某条消息失败时, Apache RocketMQ 会根据消费重试策略重新投递该消息进行故障恢复。本文介绍消费重试机制的原理、版本兼容性和使用建议。

一、应用场景​

Apache RocketMQ 的消费重试主要解决的是业务处理逻辑失败导致的消费完整性问题,是一种为业务兜底的策略,不应该被用做业务流程控制。建议以下消费失败场景使用重试机制:

推荐使用消息重试场景如下:

  • 业务处理失败,且失败原因跟当前的消息内容相关,比如该消息对应的事务状态还未获取到,预期一段时间后可执行成功。

  • 消费失败的原因不会导致连续性,即当前消息消费失败是一个小概率事件,不是常态化的失败,后面的消息大概率会消费成功。此时可以对当前消息进行重试,避免进程阻塞。

典型错误使用场景如下:

  • 消费处理逻辑中使用消费失败来做条件判断的结果分流,是不合理的,因为处理逻辑已经预见了一定会大量出现该判断分支。

  • 消费处理中使用消费失败来做处理速率限流,是不合理的。限流的目的是将超出流量的消息暂时堆积在队列中达到削峰的作用,而不是让消息进入重试链路。

二、应用目的​

消息中间件做异步解耦时的一个典型问题是如果下游服务处理消息事件失败,如何保证整个调用链路的完整性。Apache RocketMQ 作为金融级的可靠业务消息中间件,在消息投递处理机制的设计上天然支持可靠传输策略,通过完整的确认和重试机制保证每条消息都按照业务的预期被处理。

了解 Apache RocketMQ 的消息确认机制以及消费重试策略可以帮助您分析如下问题:

  • 如何保证业务完整处理消息:了解消费重试策略,可以在设计实现消费者逻辑时保证每条消息处理的完整性,避免部分消息出现异常时被忽略,导致业务状态不一致。

  • 系统异常时处理中的消息状态如何恢复:帮助您了解当系统出现异常(宕机故障)等场景时,处理中的消息状态如何恢复,是否会出现状态不一致。

三、消费重试策略概述​

消费重试指的是,消费者在消费某条消息失败后,Apache RocketMQ 服务端会根据重试策略重新消费该消息,超过一次定数后若还未消费成功,则该消息将不再继续重试,直接被发送到死信队列中。

消息重试的触发条件

  • 消费失败,包括消费者返回消息失败状态标识或抛出非预期异常。

  • 消息处理超时,包括在PushConsumer中排队超时。

消息重试策略主要行为

  • 重试过程状态机:控制消息在重试流程中的状态和变化逻辑。

  • 重试间隔:上一次消费失败或超时后,下次重新尝试消费的间隔时间。

  • 最大重试次数:消息可被重试消费的最大次数。

消息重试策略差异

根据消费者类型不同,消息重试策略的具体内部机制和设置方法有所不同,具体差异如下:

消费者类型重试过程状态机重试间隔最大重试次数
PushConsumer已就绪 处理中 待重试 提交 * 死信消费者分组创建时元数据控制。 无序消息:阶梯间隔 顺序消息:固定间隔时间消费者分组创建时的元数据控制。
SimpleConsumer已就绪 处理中 提交 死信通过API修改获取消息时的不可见时间。消费者分组创建时的元数据控制。

 

四、PushConsumer消费重试策略​

重试状态机

PushConsumer消费消息时,消息的几个主要状态如下:

Push消费状态机

  • Ready:已就绪状态。消息在Apache RocketMQ服务端已就绪,可以被消费者消费。

  • Inflight:处理中状态。消息被消费者客户端获取,处于消费中还未返回消费结果的状态。

  • WaitingRetry:待重试状态,PushConsumer独有的状态。当消费者消息处理失败或消费超时,会触发消费重试逻辑判断。如果当前重试次数未达到最大次数,则该消息变为待重试状态,经过重试间隔后,消息将重新变为已就绪状态可被重新消费。多次重试之间,可通过重试间隔进行延长,防止无效高频的失败。

  • Commit:提交状态。消费成功的状态,消费者返回成功响应即可结束消息的状态机。

  • DLQ:死信状态。消费逻辑的最终兜底机制,若消息一直处理失败并不断进行重试,直到超过最大重试次数还未成功,此时消息不会再重试,会被投递至死信队列。您可以通过消费死信队列的消息进行业务恢复。

消息重试过程中,每次重试消息状态都会经过已就绪>处理中>待重试的变化,两次消费间的间隔时间实际由消费耗时及重试间隔控制,消费耗时的最大上限受服务端系统参数控制,一般不应该超过上限时间。

消息间隔时间

最大重试次数

PushConsumer的最大重试次数由消费者分组创建时的元数据控制。

例如,最大重试次数为3次,则该消息最多可被投递4次,1次为原始消息,3次为重试投递次数。

重试间隔时间

  • 无序消息(非顺序消息):重试间隔为阶梯时间,具体时间如下:

    第几次重试与上次重试的间隔时间第几次重试与上次重试的间隔时间
    110秒97分钟
    230秒108分钟
    31分钟119分钟
    42分钟1210分钟
    53分钟1320分钟
    64分钟1430分钟
    75分钟151小时
    86分钟162小时

信息

若重试次数超过16次,后面每次重试间隔都为2小时。

  • 顺序消息:重试间隔为固定时间。

使用示例

PushConsumer触发消息重试只需要返回消费失败的状态码即可,当出现非预期的异常时,也会被SDK捕获。

SimpleConsumer simpleConsumer = null;//消费示例:使用PushConsumer消费普通消息,如果消费失败返回错误,即可触发重试。MessageListener messageListener = new MessageListener() {@Overridepublic ConsumeResult consume(MessageView messageView) {System.out.println(messageView);//返回消费失败,会自动重试,直至到达最大重试次数。return ConsumeResult.FAILURE;}};

五、SimpleConsumer消费重试策略​

重试状态机

SimpleConsumer消费消息时,消息的几个主要状态如下:

SimpleConsumer状态机

  • Ready:已就绪状态。消息在Apache RocketMQ服务端已就绪,可以被消费者消费。

  • Inflight:处理中状态。消息被消费者客户端获取,处于消费中还未返回消费结果的状态。

  • Commit:提交状态。消费成功的状态,消费者返回成功响应即可结束消息的状态机。

  • DLQ:死信状态。消费逻辑的最终兜底机制,若消息一直处理失败并不断进行重试,直到超过最大重试次数还未成功,此时消息不会再重试,会被投递至死信队列。您可以通过消费死信队列的消息进行业务恢复。

和PushConsumer消费重试策略不同的是,SimpleConsumer消费者的重试间隔是预分配的,每次获取消息消费者会在调用API时设置一个不可见时间参数 InvisibleDuration,即消息的最大处理时长。若消息消费失败触发重试,不需要设置下一次重试的时间间隔,直接复用不可见时间参数的取值。 

simpleconsumer重试

由于不可见时间为预分配的,可能和实际业务中的消息处理时间差别较大,您可以通过API接口修改不可见时间。

例如,您预设消息处理耗时最多20 ms,但实际业务中20 ms内消息处理不完,您可以修改消息不可见时间,延长消息处理时间,避免消息触发重试机制。

修改消息不可见时间需要满足以下条件:

  • 消息处理未超时

  • 消息处理未提交消费状态

如下图所示,消息不可见时间修改后立即生效,即从调用API时刻开始,重新计算消息不可见时间。 

修改不可见时间

最大重试次数

SimpleConsumer的最大重试次数由消费者分组创建时的元数据控制。

消息重试间隔

消息重试间隔=不可见时间-消息实际处理时长

SimpleConsumer 的消费重试间隔通过消息的不可见时间控制。例如,消息不可见时间为30 ms,实际消息处理用了10 ms就返回失败响应,则距下次消息重试还需要20 ms,此时的消息重试间隔即为20 ms;若直到30 ms消息还未处理完成且未返回结果,则消息超时,立即重试,此时重试间隔即为0 ms。

使用示例

SimpleConsumer 触发消息重试只需要等待即可。

 //消费示例:使用SimpleConsumer消费普通消息,如果希望重试,只需要静默等待超时即可,服务端会自动重试。List<MessageView> messageViewList = null;try {messageViewList = simpleConsumer.receive(10, Duration.ofSeconds(30));messageViewList.forEach(messageView -> {System.out.println(messageView);//如果处理失败,希望服务端重试,只需要忽略即可,等待消息再次可见后即可重试获取。});} catch (ClientException e) {//如果遇到系统流控等原因造成拉取失败,需要重新发起获取消息请求。e.printStackTrace();}

六、使用建议​

合理重试,避免因限流等诉求触发消费重试

​上文应用场景中提到,消息重试适用业务处理失败且当前消费为小概率事件的场景,不适合在连续性失败的场景下使用,例如消费限流场景。

  • 错误示例:如果当前消费速度过高触发限流,则返回消费失败,等待下次重新消费。

  • 正确示例:如果当前消费速度过高触发限流,则延迟获取消息,稍后再消费。

合理控制重试次数,避免无限重试

虽然Apache RocketMQ支持自定义消费重试次数,但是建议通过减少重试次数+延长重试间隔来降低系统压力,避免出现无限重试或大量重试的情况。

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

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

相关文章

记录 | mac安装node

第一种方法(下载官网对应 node 版本的 .pkg文件) 访问nodejs官网&#xff08;Node.js 中文网&#xff09;选择合适的版本 双击刚下载的 .pkg 文件&#xff0c;进行安装 安装完成后检查 node 和 npm 的版本 node -v npm -v第二种方法,是使用 Homebrew 使用命令安装 //默认安…

【Oracle】创建表

目录 方法一&#xff1a;CREATE TABLE 语法 创建表示例1&#xff1a;创建stuinfo(学生信息表) 创建表示例2&#xff1a;添加stuinfo(学生信息表)约束 方法二&#xff1a;CREATE TABLE AS 语法 创建表示例3&#xff1a; 创建表示例4&#xff1a;实现对select查询的结果进行…

Impala4.x源码阅读笔记(一)——HdfsTextScanner解析

前言 本文为笔者个人阅读Apache Impala源码时的笔记&#xff0c;仅代表我个人对代码的理解&#xff0c;个人水平有限&#xff0c;文章可能存在理解错误、遗漏或者过时之处。如果有任何错误或者有更好的见解&#xff0c;欢迎指正。 在文章Impala3.4源码阅读笔记&#xff08;七…

Java中常见需要重写equals方法的类

目录 导言 一、自定义类 二、集合类 三、字符串类 四、数组类 五、枚举类 结论 导言 在Java编程中&#xff0c;equals方法是用来比较两个对象是否相等的关键方法之一。然而&#xff0c;在某些情况下&#xff0c;Java提供的默认equals方法可能无法满足我们的需求。因此&a…

ipa文件怎么去除包体内的插件在线签名工具步骤

当开发者完成iOS应用的开发并构建完成后&#xff0c;应用程序会被打包为一个.ipa文件&#xff0c;这是一个iOS App Store的安装包格式。在某些情况下&#xff0c;开发者可能需要去除.ipa文件中包含的插件&#xff08;通常指的是app extension、frameworks或watch apps等&#x…

商城后台管理系统--->新闻简报(富文本编辑器,文章,图片上传)

在商城的项目里面需要添加新闻&#xff0c;使用富文本编辑器&#xff0c;我用的是 wangEditor这个编辑器挺好用的&#xff0c;而且也方便简单&#xff0c;官网也是中文的wangEditor 这是做的添加新闻的页面 我用的是SCUI框架,引入的是npm,具体可看官网 npm install wangedit…

IDEA快捷键注释代码设置不从行开头开始

我们平时在用IDEA开发项目时会发现&#xff0c;快捷键注释的//总是在代码的行开头上面&#xff0c;如下图所示&#xff1a; 这样就显得代码很不美观&#xff0c;那如何才能使注释//贴紧代码呢&#xff1f;需要在IDEA中进行如下配置&#xff1a; 点击Apply之后就可以了&#xff…

Goldstein枝切法对存在间断相位缺陷的解缠研究

摘要: Goldstein枝切法作为相位解缠中路径积分法的重要算法之一&#xff0c;其解缠结果易受到噪声或间断相位缺陷所引起的残差点影响。为了研究相位间断缺陷对解缠算法的影响&#xff0c;模拟了具有间断相位缺陷的数据&#xff0c;采用 Gold-stein枝切法进行了系统的解缠研究。…

springboot发送邮件,内容使用thymeleaf模板引擎排版

springboot发送邮件,内容使用thymeleaf模板引擎排版 1、导入jar包2、yml设置3、收件人以及收件信息设置4、发邮件service5、模版页面6、controller 1、导入jar包 <!--发送邮件--><dependency><groupId>org.springframework.boot</groupId><artifac…

十五 动手学深度学习v2计算机视觉 ——全连接神经网络FCN

文章目录 FCN FCN 全卷积网络先使用卷积神经网络抽取图像特征&#xff0c;然后通过卷积层将通道数变换为类别个数&#xff0c;最后通过转置卷积层将特征图的高和宽变换为输入图像的尺寸。 因此&#xff0c;模型输出与输入图像的高和宽相同&#xff0c;且最终输出通道包含了该空…

虚幻学习笔记17—C++委托(单播)

一、前言 相比“代理”这个名词我更喜欢叫“委托”&#xff0c;虚幻的委托分为三类&#xff0c;分别为单播、多播和动态多播。单播顾名思义就是一次只能绑定一个函数的委托&#xff0c;多播能一次性绑定多个&#xff0c;动态多播即可以在蓝图中进行动态的绑定且可以绑定多个。 …

jmeter,动态参数之随机数、随机日期

通过函数助手&#xff0c;执行以下配置&#xff1a; 执行后的结果树&#xff1a; 数据库中也成功添加了数据&#xff0c;对应字段是随机值&#xff1a;