发送重试与流控策略
本文档介绍了 Apache RocketMQ 的消息发送重试机制和限流机制。
背景信息
消息发送重试
Apache RocketMQ 的发送重试机制解答了以下问题:
如果部分节点故障,消息是否还能发送?
重试请求是否会阻塞调用线程?
发送重试有哪些缺陷?
限流
Apache RocketMQ 的限流机制解答了以下问题:
在什么情况下会触发限流?
触发限流时客户端的表现如何?
如何避免触发限流以及如何处理意外的限流?
消息发送重试
发送重试简介
当 Apache RocketMQ 的生产者客户端调用 Broker 发送消息时,可能会因为网络故障或服务异常等原因导致调用失败。为了确保消息的可靠性,Apache RocketMQ 在客户端 SDK 中提供了内置逻辑,会自动重试失败的请求,直到请求成功。
同步和异步发送模式均支持消息发送重试。
触发条件
发送重试可由以下任一条件触发:
客户端调用失败或请求超时。
网络异常导致连接失败或请求超时。
Broker 节点关闭或重启导致连接断开。
因 Broker 运行缓慢导致请求超时。
Broker 返回错误码。
逻辑错误:由运行逻辑不当导致的错误。
限流:因流量过大触发的限流。
对于事务消息,仅执行透明重试 (Transparent retries)。在网络异常或超时场景下,不执行任何重试。
重试流程
您可以在生产者初始化消息时指定最大重试次数。当出现上述触发条件时,生产者客户端会尝试重新发送消息,直到消息发送成功或达到最大重试次数。如果最后一次重试仍失败,则会返回调用错误。
同步发送:调用线程将被阻塞,直到重试成功或最后一次重试失败。如果最后一次重试失败,系统将返回错误码和异常。
异步发送:调用线程不会被阻塞。调用结果以异常事件或成功事件的形式返回。
重试间隔
除由限流触发的重试外,消息在失败后会立即重试。
如果重试是由限流触发的,消息将按照指数退避协议中指定的间隔进行重试。指数退避算法使用以下参数来控制重试行为:
INITIAL_BACKOFF(初始退避):指定第一次失败和第一次重试之间的间隔。默认值:1 秒。
MULTIPLIER(乘数):指定每次重试失败后间隔的乘数因子。默认值:1.6。
JITTER(抖动):指定随机化间隔的因子。默认值:0.2。
MAX_BACKOFF(最大退避):指定间隔的上限。默认值:120 秒。
MIN_CONNECT_TIMEOUT(最小连接超时):指定最小间隔。默认值:20 秒。
建议采用以下算法:
ConnectWithBackoff()
current_backoff = INITIAL_BACKOFF
current_deadline = now() + INITIAL_BACKOFF
while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT))!= SUCCESS)
SleepUntil(current_deadline)
current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
current_deadline = now() + current_backoff + UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)
更多信息,请参见 connection-backoff.md。
限制
链路阻塞评估:从重试机制可以看出,生产者只能配置重试过程中的最大重试次数。如果系统异常触发了 SDK 的内置重试逻辑,Broker 必须等待最终重试结果,发送请求链路会被阻塞。因此,必须为每次调用评估超时时间和最大重试次数,以防止重试导致链路阻塞。
最终异常处理:Apache RocketMQ 客户端的内置发送重试机制不能保证失败的消息一定能成功发送。如果最后一次重试仍然失败,调用者必须捕获异常并提供冗余保护,以防止消息发送结果的不一致。
重复消息:当 Apache RocketMQ 生产者客户端重新发送消息时,客户端不知道该消息在 Broker 上的处理结果(即使之前已显示失败)。因此,Broker 上可能会存在重复消息。请确保您的业务逻辑能够妥善处理此类情况。
限流
限流简介
当系统容量使用率超过阈值时,Apache RocketMQ Broker 会拒绝请求并返回错误,以避免底层资源负载过重。
触发条件
Apache RocketMQ 的限流机制由以下任一条件触发:
存储压力过大:如《消费进度管理》的“工作机制”部分所述,消费者组从队列的最大偏移量开始消费消息。如果要求消费者组从更早的时间点开始消费,队列的存储压力会激增,从而触发限流。这常见于回溯场景,例如新业务上线时。
Broker 上存在大量未消费消息:如果消费者无法以消息进入队列的速率进行消费,请求会在队列中堆积。如果堆积的消息数量超过阈值,系统会触发限流以减轻下游系统的负担。
行为
触发限流时,生产者客户端会收到以下错误消息和异常:
回复代码:530
回复文本:TOO_MANY_REQUESTS
收到这些错误后,客户端将根据指数退避协议重试消息。更多信息,请参见 消息发送重试。
建议
建议:
如何避免触发限流:使用可观测性指标监控系统容量,并相应地扩展底层资源。
如何处理限流:如果触发了限流且客户端的内置重试流程失败,您可以暂时将调用切换到其他系统。