消息发送重试与限流策略
本文描述了 Apache RocketMQ 的消息发送重试机制和限流机制。
背景
消息发送重试
Apache RocketMQ 的发送重试机制回答了以下问题
如果某些节点出现故障,消息是否可以发送?
重试请求会阻塞调用线程吗?
发送重试有哪些缺点?
限流
Apache RocketMQ 的限流机制回答了以下问题
在什么情况下会触发限流?
触发限流时客户端的行为是什么?
如何避免触发限流以及如何处理意外的限流?
消息发送重试
发送重试简介
当 Apache RocketMQ 的生产者客户端调用 Broker 发送消息时,调用可能会因网络故障或服务异常等原因而失败。为确保消息可靠性,Apache RocketMQ 在客户端 SDK 中提供了内置逻辑,以重试失败的请求,直到请求成功。
消息发送重试在同步和异步发送模式下均受支持。
触发条件
发送重试可能由以下任一条件触发
客户端调用失败或请求超时。
网络异常导致连接失败或请求超时。
Broker 节点关闭或正在重启导致连接关闭。
Broker 运行缓慢导致请求超时。
Broker 返回错误码。
逻辑错误:由运行逻辑不正确引起的错误。
限流:由流量过大触发的限流。
对于事务消息,仅执行透明重试。在网络异常或超时场景下不执行重试。
重试流程
您可以在生产者初始化消息时,在生产者上指定最大重试次数。当出现上述任一触发条件时,生产者客户端会尝试再次发送消息,直到消息发送成功或达到最大重试次数。如果在最后一次重试时仍然失败,则返回调用错误。
同步发送:调用线程被阻塞,直到重试成功或最后一次重试失败。如果最后一次重试失败,系统将返回错误码和异常。
异步发送:调用线程不被阻塞。调用结果以异常事件或成功事件的形式返回。
重试间隔
消息在失败后立即重试,除非重试是由限流触发的。
如果重试是由限流触发的,消息将按照指数退避协议中指定的间隔进行重试。指数退避算法使用以下参数来控制重试行为
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 上未消费消息过多:如果消费者无法以与消息发送速率相同的速度消费消息,请求会在队列中堆积。如果堆积的消息数量超过阈值,将触发限流以减轻下游系统的负担。
行为
触发限流时,生产者客户端会收到以下错误消息和异常
reply-code:530
reply-text:TOO_MANY_REQUESTS
收到这些信息后,客户端会根据指数退避协议重试消息。更多信息,请参阅消息发送重试。
建议
建议
如何避免触发限流:使用可观测指标监控系统容量并相应地扩展底层资源。
如何处理限流:如果触发限流且客户端内置的重试流程失败,您可以暂时将调用切换到另一个系统。