在 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 Receives
和 Dead Letter Queue
关联)。因此,一种可能的解决方法是自行处理故障并在每个 re-queue 上逐步设置消息特定延迟(更多 here)(这包括处理 [=43= 中的 retry-count ] 可能不使用 JMS)。请注意,这可能会产生额外费用。
旁注:向 queue 或可见性超时添加延迟对阅读消息时失败之间的延迟没有帮助。
我想在 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 Receives
和 Dead Letter Queue
关联)。因此,一种可能的解决方法是自行处理故障并在每个 re-queue 上逐步设置消息特定延迟(更多 here)(这包括处理 [=43= 中的 retry-count ] 可能不使用 JMS)。请注意,这可能会产生额外费用。
旁注:向 queue 或可见性超时添加延迟对阅读消息时失败之间的延迟没有帮助。