跳至主要内容
版本: 5.0

发送重试和限流策略

本主题描述了 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

收到这些后,客户端会根据指数退避协议重试消息。有关更多信息,请参阅消息发送重试

建议

建议

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

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