AWS Lambda被单次SQS消息触发两次的问题排查与解决求助
SQS触发Lambda时单条消息重复触发的问题排查与解决
我之前维护一套以SQS为事件源的Lambda异步处理系统时,碰到过和你完全一样的情况——单条带唯一ID的消息在100毫秒内被两个Lambda实例处理,而且绝对不是失败重试的场景。折腾了好一阵才理清原因,分享下我的排查思路和解决方法:
可能的原因分析
- SQS短轮询的局限性:默认情况下SQS使用短轮询,当有多台SQS服务器存储消息时,短轮询只会随机查询部分服务器,这就可能导致同一个消息被多个拉取请求(来自不同Lambda实例)同时获取到,毕竟你的消息刚写入还没完全同步到所有节点。
- SQS内部的消息复制延迟:当消息刚被写入SQS时,系统正在后台复制消息到多个冗余节点,这时候如果有多个拉取请求进来,不同节点可能还没同步状态,就会把同一条消息返回给不同的请求。
- Lambda并发拉取的时间窗口:如果你的Lambda执行速度极快(比如几十毫秒就完成),而SQS的可见性超时设置得刚好和执行时间差不多,极端情况下第一个实例还没来得及调用
DeleteMessage,SQS可能已经把消息标记为可再次获取(不过这种情况更少见,100毫秒内的重复更可能是轮询问题)。
具体的解决方法
- 启用SQS长轮询:这是最直接的优化,把SQS队列的长轮询等待时间设置为1-20秒(比如5秒)。长轮询会让SQS检查所有可用的消息存储节点,确保不会重复返回同一条消息,从根源上减少这类触发重复的概率。你可以在SQS控制台的队列配置里开启,或者用
aws sqs set-queue-attributes命令设置ReceiveMessageWaitTimeSeconds参数。 - 合理设置可见性超时:确保SQS的可见性超时至少是Lambda最大执行时间的3倍。比如你的Lambda最多需要500毫秒处理完成,那可见性超时至少设为1.5秒以上,给Lambda足够的时间完成处理并删除消息,避免消息在处理过程中重新变为可见。
- 实现幂等性处理(必做兜底):不管SQS和Lambda的配置怎么优化,分布式系统里的重复消息都是无法完全避免的,所以必须在业务逻辑层实现幂等。比如用你的内部唯一ID作为键,在处理前先查询Redis或DynamoDB:如果这个ID已经被处理过,直接返回成功;如果没处理过,就执行业务逻辑,处理完成后标记这个ID为已处理。
- 检查Lambda事件源映射配置:如果你的Lambda是通过事件源映射关联SQS的,确保
BatchSize设置合理,并且可以考虑调整MaximumBatchingWindowInSeconds(比如设为1秒),让SQS攒一点消息再触发Lambda,减少频繁的拉取请求,也能降低重复触发的概率。 - 如果是FIFO队列:确保正确配置去重:如果你的SQS是FIFO类型,一定要给每条消息设置唯一的
MessageDeduplicationId,同时开启内容-based去重,这样SQS会自动帮你过滤掉重复的消息。
内容的提问来源于stack exchange,提问作者Rishi Ambwani
相关产品推荐
相关产品推荐

