[RocketMQ] 发送重试机制与消费重试机制~
发送重试
RocketMQ 客户端发送消息时,由于网络故障等因素导致消息发送失败,这时客户端SDK会触发重试机制,尝试重新发送以达到调用成功的效果。
触发条件
- 客户端消息发送请求失败或超时。
- 服务端节点处于重启或下线状态。
- 服务端运行慢造成请求超时。
- 服务端返回错误代码(逻辑错误/流控错误)。
重试流程
当重试机制触发时,客户端会按照设置的重试次数一直重新尝试发送消息,直到消息发送成功或达到最大重试次数,在最后一次重试失败后会返回调用错误响应。
重试间隔
如果触发原因不是系统流控错误,则会立即进行重试,无间隔时间。如果是系统流控错误,则会按照指数退避策略进行延迟重试:
INITIAL_BACKOFF: 第一次失败重试前后需等待多久,默认值:1秒。
MULTIPLIER:指数退避因子,即退避倍率,默认值:1.6。
JITTER:随机抖动因子,默认值:0.2。
MAX_BACKOFF:等待间隔时间上限,默认值:120秒
MIN_CONNECT_TIMEOUT:最短重试间隔,默认值:20秒。
系统流控
RocketMQ服务端在系统资源紧缺的时候,会通过快速返回错误来避免底层资源承受更高压力。
触发条件:
- 存储压力过大:队列存储压力过大时。
- 服务端请求任务排队溢出:如果消费者消费能力不足,会导致队列中堆积大量消息,当消息超过一定数量后会触发流控。
消费重试
当消费者返回错误状态或超时未返回状态时,RocketMQ 会根据消费重试策略重新投递消息。当重试超过一定次数后,如果还未消费成功,则不再继续重试,直接将消息发送到死信队列中。
主要概念
- 重试过程状态机:控制消息在重试流程中的状态变化逻辑。
- 重试间隔:下一次重新尝试消费的时间间隔。
- 最大重试次数:消息可以被重试消费的最大次数。
不同的消费者类型,消息重试策略略有不同:
消费者类型 | 状态机 | 重试间隔 | 重试次数 |
---|---|---|---|
PushConsumer | 就绪/处理中/待重试/提交/死信 | 创建分组时控制。无序消息使用阶梯间隔,顺序消息使用固定间隔。 | 创建分组时控制 |
SimpleConsumer | 就绪/处理中/提交/死信 | 通过API修改。 | 创建分组时控制 |
PushConsumer重试策略
重试状态机
-
就绪(Ready):消息在 RocketMQ 服务端已就绪,可以被消费者消费。
-
处理中(Inflight):消息被消费者获取,但还未返回消费结果的状态。
-
待重试(WaitingRetry):当消息处理失败或超时时,会触发重试逻辑。如果重试次数未达到上限,则该消息状态变为待重试,等待重试间隔后,消息重新变为已就绪状态以重新消费。
待重试是 PushConsumer 特有的状态。
-
提交(Commit):消费者完成消费逻辑并返回成功响应。
-
死信(DLQ):消费逻辑的最终兜底机制,当消息重试次数达到上限还未成功,则不会再重试,而是投递到死信队列。死信队列可以被消费从而进行业务恢复。
重试时间间隔
-
无序消息:重试时间间隔为阶梯时间
重试次数 间隔时间 重试次数 间隔时间 1 10秒 9 7分钟 2 30秒 10 8分钟 3 1分钟 11 9分钟 4 2分钟 12 10分钟 5 3分钟 13 20分钟 6 4分钟 14 30分钟 7 5分钟 15 1小时 8 6分钟 16 2小时 如果重试次数超过16,则后面每次重试间隔为2小时。
-
顺序消息:重试间隔为固定时间。
SimpleConsumer重试策略
重试状态机
- 就绪(Ready):消息在 RocketMQ 服务端已就绪,可以被消费者消费。
- 处理中(Inflight):消息被消费者获取,但还未返回消费结果的状态。
- 提交(Commit):消费者完成消费逻辑并返回成功响应。
- 死信(DLQ):消费逻辑的最终兜底机制,当消息重试次数达到上限还未成功,则不会再重试,而是投递到死信队列。死信队列可以被消费从而进行业务恢复。
不可见时间
SimpleConsumer 的重试间隔是通过不可见时间来控制的,不可见时间是在调用获取消息API时设置的,可以理解为消息最大处理时长,当消费时间达到了不可见时间仍未返回消息或已经在此前返回失败消息时,则触发重试。
例如设置的不可见时间为50ms,实际在30ms的时候已经返回失败消费状态,那么此时会间隔20ms后触发重试机制。
不可见时间支持在消费处理逻辑中动态修改,修改后立即生效,但修改的实际必须满足一下两个条件:
- 消息处理未超时。
- 消息处理未提交消费状态。