在 AWS 中为 SQS 定义 BackoffStrategy

Defining BackoffStrategy for SQS in AWS

我想在 Spring 应用程序中为 sqs 设置退避策略。我所做的是:

    @Bean
    public ConnectionFactory sqsConnectionFactory() {

        PredefinedBackoffStrategies.ExponentialBackoffStrategy backoffStrategy = new PredefinedBackoffStrategies.ExponentialBackoffStrategy(3, 27);
        RetryPolicy retryPolicy = new RetryPolicy(PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION, backoffStrategy, PredefinedRetryPolicies.DEFAULT_MAX_ERROR_RETRY, false);
        return SQSConnectionFactory.builder()
                .withRegion(Region.getRegion(Regions.fromName(region)))
                .withAWSCredentialsProvider(new DefaultAWSCredentialsProviderChain())
                .withClientConfiguration(new ClientConfiguration().withRetryPolicy(retryPolicy))
                .build();
    }

,但是没有效果。我通过简单的 @JmsListener 方法从 SQS 队列中读取。在这个方法中有调用其他 api。这个apireturns我404错误。然后就是重试,不过是即时重试。为什么会这样,如何使用指数退避策略正确配置它?它正在重试,但不是指数延迟时间。

您的代码 ClientConfiguration 中设置的退避策略用于为 AWS 客户端重试连接 AWS 服务提供延迟。这意味着如果(比如出于某种原因)AWS SQS 客户端无法连接到 AWS SQS 服务以获取消息(或轮询新消息),则将使用您设置的策略。如果发生此类故障,则应在配置的 ExponentialBackoffStrategy 提供的延迟后进行下一次尝试。有关详细信息,请参阅 official documentation here.

立即重试的原因

对于您的情况,底层客户端(Spring 的 @JmsListener 使用)已经从 SQS 服务获取消息。这一步的失败将使用 ExponentialBackoffStrategy。之后的失败(如 404 之后抛出的异常)将触发对 SQS 服务的失败确认,并且该服务将使消息可见以立即再次使用。

如何将退避策略与重新投递相关联

遗憾的是,该策略无法与消息消费失败相关联。 所需的延迟实际上是 JMS 2.0 规范的 redelivery-delay。但是您似乎使用的 SQS JMS 提供程序是这个 https://github.com/awslabs/amazon-sqs-java-messaging-lib,它是 JMS 1.1 实现。以下是从他们的文档中引用的相同内容:

This project builds on top of the AWS SDK for Java to use Amazon SQS as the JMS (as defined in 1.1 specification) provider

此外,SQS 在他们的 redrive-policy 中没有任何类似 redelivery-delay 的东西(只有 Maximum ReceivesDead Letter Queue 关联)。因此,一种可能的解决方法是自行处理故障并在每个 re-queue 上逐步设置消息特定延迟(更多 here)(这包括处理 [=43= 中的 retry-count ] 可能不使用 JMS)。请注意,这可能会产生额外费用。

旁注:向 queue 或可见性超时添加延迟对阅读消息时失败之间的延迟没有帮助。