发送重试和限流策略
本主题描述了 Apache RocketMQ 的消息发送重试机制和限流机制。
背景
消息发送重试
Apache RocketMQ 的发送重试机制回答了以下问题
如果某些节点出现故障,消息是否可以发送?
重试请求是否会阻塞调用线程?
发送重试有哪些缺点?
限流
Apache RocketMQ 的限流机制回答了以下问题
在什么情况下会触发限流?
触发限流时,客户端的行为是什么?
如何避免触发限流以及如何处理意外限流?
消息发送重试
发送重试简介
当 Apache RocketMQ 的生产者客户端调用代理发送消息时,由于网络故障或服务异常等原因,调用可能会失败。为了确保消息可靠性,Apache RocketMQ 在客户端 SDK 中提供了内置逻辑,以重试失败的请求,直到请求成功。
消息发送重试在同步和异步发送模式下都受支持。
触发条件
发送重试可以由以下条件之一触发
客户端的调用失败或请求超时。
网络异常导致连接失败或请求超时。
由于代理节点关闭或正在重启,连接被关闭。
由于代理运行缓慢,请求超时。
代理返回错误代码。
逻辑错误:由不正确的运行逻辑引起的错误。
限流:由流量过大触发的限流。
对于事务消息,只执行透明重试。在网络异常或超时情况下不执行重试。
重试过程
您可以在生产者初始化消息时,在生产者上指定最大重试次数。当发生上述触发条件之一时,生产者客户端会尝试再次发送消息,直到消息发送成功或达到最大重试次数。如果最后一次重试仍然失败,则返回调用错误。
同步发送:调用线程被阻塞,直到重试成功或最后一次重试失败。如果最后一次重试失败,系统将返回错误代码和异常。
异步发送:调用线程不会被阻塞。调用结果将作为异常事件或成功事件返回。
重试间隔
消息在发生故障时会立即重试,除非重试是由限流触发的。
如果重试是由限流触发的,则消息将按照指数退避协议中指定的间隔进行重试。指数退避算法使用以下参数来控制重试行为
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 的内置重试逻辑,代理必须等待最终的重试结果,发送请求链接就会被阻塞。因此,您必须评估每次调用的超时时间和最大重试次数,以防止重试阻塞链接。
最终异常处理:Apache RocketMQ 客户端的内置发送重试机制不能保证失败的消息能够成功发送。如果最后一次重试仍然失败,调用者必须捕获异常并提供冗余保护,以防止消息发送结果不一致。
重复消息:当 Apache RocketMQ 生产者客户端重新发送消息时,客户端不知道代理上可能失败的消息的处理结果。因此,代理上可能存在重复消息。确保您的业务逻辑能够正确处理此类情况。
限流
限流简介
当系统容量使用率超过阈值时,Apache RocketMQ 代理会拒绝请求并返回错误,以避免过度占用底层资源。
触发条件
Apache RocketMQ 的限流机制由以下条件之一触发
存储压力过大:如消费者进度管理的“工作机制”部分所述,消费者组从队列的最大偏移量开始消费消息。如果消费者组需要从更早的时间点开始消费,则队列的存储压力会激增,从而触发限流。这发生在回溯场景中,例如新业务推出。
代理上未消费的消息过多:如果消费者无法以与发送到它们的消息相同的速率消费消息,则请求会在队列中堆积。如果堆积的消息数量超过阈值,则会触发限流,以减轻下游系统的负担。
行为
当触发限流时,生产者客户端会收到以下错误消息和异常
reply-code:530
reply-text:TOO_MANY_REQUESTS
收到这些后,客户端会根据指数退避协议重试消息。有关更多信息,请参阅消息发送重试。
建议
建议
如何避免触发限流:使用可观察指标监控系统容量并相应地扩展底层资源。
如何处理限流:如果触发了限流,并且客户端的内置重试过程失败,您可以暂时将调用切换到另一个系统。