跳转至主要内容
版本: 5.0

发送重试与流控策略

本文档介绍了 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

收到这些错误后,客户端将根据指数退避协议重试消息。更多信息,请参见 消息发送重试

建议

建议:

  • 如何避免触发限流:使用可观测性指标监控系统容量,并相应地扩展底层资源。

  • 如何处理限流:如果触发了限流且客户端的内置重试流程失败,您可以暂时将调用切换到其他系统。