You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS SQS队列触发Lambda重复执行问题排查求助

SQS触发Lambda重复执行问题排查与解决

我有一个服务调用AWS SQS队列触发Lambda执行,但偶尔会出现同一队列消息触发Lambda两次的异常情况。Lambda日志显示首次调用带有MessageDeduplicationId字段,第二次调用时该字段消失,问题并非每次发生,但必须彻底解决重复执行的问题。

消息发送代码

import aws from 'aws-sdk';
import { v4 as uuidv4 } from 'uuid';

import * as awsConfig from '../config/aws';

const accessKeyId = awsConfig.accessKeyId;
const secretAccessKey = awsConfig.secretAccessKey;
const region = awsConfig.generalRegion;

class SqsMessenger {
  sqs: aws.SQS;
  constructor() {
    this.sqs = new aws.SQS();
  }

  send(body: any, queueUrl: string, groupId?: string) {
    const params: aws.SQS.Types.SendMessageRequest = {
      MessageBody: JSON.stringify(body),
      MessageGroupId: groupId || uuidv4(),
      MessageDeduplicationId: uuidv4(),
      QueueUrl: queueUrl,
    };

    return new Promise((resolve, reject) => {
      this.sqs.sendMessage(params, (error: aws.AWSError, data: aws.SQS.SendMessageResult) => {
        if (error) {
          return reject(error);
        }
        resolve(data);
      });
    });
  }
}

export const sqs = new SqsMessenger();

问题根源分析

  • 队列类型与去重字段不匹配:MessageDeduplicationId仅对SQS FIFO队列生效,如果你的队列是标准队列,该字段不会产生任何去重效果。SQS标准队列因分布式架构特性,可能出现消息重复存储的情况,进而触发Lambda多次执行。
  • 消息未正确确认:Lambda执行超时、抛出未捕获异常时,SQS会将消息重新放回队列,导致二次触发。日志中第二次调用无MessageDeduplicationId,大概率是消息被重新投递时,原去重字段未被保留(标准队列不存储该字段)。
  • 随机去重ID的局限性:即使是FIFO队列,用随机UUID生成MessageDeduplicationId无法针对同一业务请求的重复发送进行去重,若服务端因重试重复发送同一业务消息,SQS会认为是新消息而接收。

解决方案

1. 匹配队列类型配置去重规则

  • 使用FIFO队列:
    • 确保队列开启FIFO模式,同时可开启Content-Based Deduplication(自动基于消息内容生成去重ID),或改用业务唯一标识生成MessageDeduplicationId(比如订单ID+时间戳),确保同一业务请求的重复发送在5分钟去重窗口内被拦截。
    • 避免随机生成MessageGroupId,同一业务流的消息使用固定分组ID,保证顺序性的同时避免不必要的分组分散。
  • 使用标准队列:
    • 标准队列不支持服务端去重,必须在Lambda端实现幂等性:
      1. 为每个业务消息分配唯一业务ID(如请求ID、订单ID);
      2. Lambda执行前,先查询数据库/Redis确认该ID是否已处理;
      3. 已处理则直接返回成功,未处理则执行业务逻辑并标记ID为已处理。

2. 确保消息处理的可靠性

  • 调整Lambda超时时间:设置为小于SQS的VisibilityTimeout(建议Lambda超时=VisibilityTimeout-5秒),给Lambda足够的处理时间,避免因超时导致消息重投。
  • 捕获Lambda所有异常:在代码中添加全局异常处理逻辑,处理失败时可将消息转发至死信队列(DLQ),避免无意义的重复重试。

3. 优化去重ID生成逻辑(FIFO队列适用)

将随机UUID替换为基于业务标识的去重ID,示例:

// 假设body中包含唯一业务ID字段businessId
MessageDeduplicationId: `${body.businessId}-${Date.now()}`,

这样能确保同一业务请求的重复发送会被SQS识别并丢弃,从源头避免重复消息。

内容的提问来源于stack exchange,提问作者Ezequiel Jaramillo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:20:35