Spring Boot中SQS FIFO监听器提前接收消息问题排查
AWS SQS FIFO队列同Group ID消息乱序处理问题解决
问题背景
基于Spring Boot的AWS SQS FIFO应用,要求同Group ID的消息(m1、m2、m3)按m1→m2→m3顺序处理:m2需等m1完全处理完成,m3需等m1、m2处理完成。但实际运行中,m1被接收后,m2、m3几乎同时被接收并完成处理,违反FIFO顺序要求。
当前核心配置信息:
- 监听器删除策略设为
SqsMessageDeletionPolicy.NEVER,计划手动删除消息 - SQS客户端配置代码:
import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.WebIdentityTokenCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.sqs.AmazonSQSAsync; import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration public class AmazonSQSConfiguration { @Primary @Bean("sqsClient") public AmazonSQSAsync buildAmazonSQSAsync() { return AmazonSQSAsyncClientBuilder .standard() .withRegion(Regions.AP_SOUTHEAST_1) .withCredentials(awsCredentialsProvider()) .build(); } public AWSCredentialsProvider awsCredentialsProvider() { return WebIdentityTokenCredentialsProvider.builder() .roleSessionName("test-order") .build(); }
- 依赖配置:
<!--aws related dependencies--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-aws</artifactId> <version>2.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-aws-messaging</artifactId> <version>2.2.6.RELEASE</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>1.12.161</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
- 消息接收日志:
| message | publish time | listen time |
|---|---|---|
| m1 | 2022年8月19日 下午3:16:44.131 | 2022年8月19日 下午3:26:40.684 |
| m2 | 2022年8月19日 下午3:16:44.137 | 2022年8月19日 下午3:26:40.684 |
| m3 | 2022年8月19日 下午3:16:44.139 | 2022年8月19日 下午3:26:40.686 |
解决建议
1. 限制监听器并发数为1
Spring Cloud AWS SQS监听器默认多线程并发拉取消息,会导致同Group ID的消息被不同线程同时处理。必须将并发数和单次拉取消息数设为1,确保同一时间仅处理一条同Group ID的消息。
方式一:在监听器注解上配置
@SqsListener(value = "${sqs.fifo.queue.name}", deletionPolicy = SqsMessageDeletionPolicy.NEVER, maxNumberOfMessages = "1", concurrency = "1") public void handleMessage(String message, @Header("ReceiptHandle") String receiptHandle) { // 消息处理逻辑 // 处理完成后手动删除消息 amazonSQS.deleteMessage(new DeleteMessageRequest(queueUrl, receiptHandle)); }
方式二:全局配置文件设置
cloud.aws.messaging.sqs.listener.max-number-of-messages=1 cloud.aws.messaging.sqs.listener.concurrency=1
2. 调整消息可见性超时时间
当消息被拉取后,SQS会将其设为不可见状态,直到可见性窗口过期。如果窗口过短,未处理完成的消息会重新回到队列,被其他线程拉取。建议将可见性超时设置为消息处理时间的2-3倍,避免消息提前重新入队。
3. 严格控制手动删除时机
必须在消息**完全处理完成(无异常)**后再调用deleteMessage方法。如果处理过程中抛出异常,需根据业务需求选择延长消息可见性或让消息重新入队:
public void handleMessage(String message, @Header("ReceiptHandle") String receiptHandle) { try { // 执行核心业务逻辑 processMessage(message); // 处理成功后删除消息 amazonSQS.deleteMessage(queueUrl, receiptHandle); } catch (Exception e) { // 处理失败,延长消息可见性以便重试 amazonSQS.changeMessageVisibility(queueUrl, receiptHandle, 120); // 延长120秒 throw e; // 抛出异常触发框架重试机制 } }
4. 确认FIFO队列及消息Group ID配置
- 确保队列是标准FIFO类型(名称以
.fifo结尾),且已启用分组ID支持 - 发送消息时,同批次需处理的消息必须设置相同的Group ID,否则SQS无法保证顺序
5. 升级依赖版本
当前使用的spring-cloud-starter-aws 2.2.6.RELEASE版本较旧,可能存在FIFO队列处理的兼容问题。建议升级到稳定新版本(如2.3.2.RELEASE),同时确保aws-java-sdk版本与之兼容。
内容的提问来源于stack exchange,提问作者kevin_Aberathna
相关产品推荐
相关产品推荐

