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

特定时段AWS Lambda时长突增问题排查求助

问题背景与疑问

我运行着一个主AWS Lambda函数,负责从AWS RDS PostgreSQL存储和检索数据,另有5个不同触发间隔的Lambda函数调用它向RDS写入数据。日常主Lambda调用量约100~150K次,平均时长500ms以内,但每逢周六时长会突增至4145ms。我的几点疑问:

  • 是否由冷启动导致?我的初始化时长平均为700ms;
  • 是否是数据库读写缓慢?数据库读操作平均5秒,写操作平均400ms,使用Sequelize框架;
  • PostgreSQL配置是否存在问题?

请求代码

module.exports.postMatch = async (req, res) => {
  // console.log("data", req.body);
  if (req.body == null) {
    console.log("no match data");
    return res.json("no match data");
  } else {
    const Week = null;
    const Stage = null;
    const Round = null;
    const Season = null;
    const matches = req.body;
    const StaticID = matches["@static_id"];
    const MatchID = matches["@id"];
    let date = req.body["@formatted_date"];
    date = date.split(".").reverse().join(".");
    const time = req.body["@time"] === "TBA" ? "00:00" : req.body["@time"];
    const MatchDateString = moment(
      `${date} ${time}`,
      "YYYY-MM-DD HH:mm:ss"
    ).format();
    const MatchDate = moment(MatchDateString, "YYYY-MM-DD HH:mm:ss");
    const Status = matches["@status"];
    const TournamentID = matches.id;
    const TournamentName = matches.leagueNameOnly;
    const Team1Name = matches.localteam["@name"];
    const Team1ID = matches.localteam["@id"];
    const Team2Name = matches.visitorteam["@name"];

    const Team2ID = matches.visitorteam["@id"];
    const Team1Score = matches.localteam["@goals"];
    const Team2Score = matches.visitorteam["@goals"];
    const Team1PenaltyScore = matches.penalty
      ? matches.penalty["@localteam"]
      : null;
    const Team2PenaltyScore = matches.penalty
      ? matches.penalty["@visitorteam"]
      : null;
    //  [0-0] => ['0','-','0']
    const HalfTimeScore = matches.ht
      ? matches.ht["@score"]
          .replace("[", "")
          .replace("[", "")
          .replace(/\s/g, "")
          .trim()
          .split("")
      : null;
    //  [0-0] => ['0','-','0']
    const FullTimeScore = matches.ft
      ? matches.ft["@score"]
          .replace("[", "")
          .replace("[", "")
          .replace(/\s/g, "")
          .trim()
          .split("")
      : null;
    //  [0-0] => ['0','-','0']
    const ExtraTimeScore = matches.et
      ? matches.et["@score"]
          .replace("[", "")
          .replace("[", "")
          .replace(/\s/g, "")
          .trim()
          .split("")
      : null;

    const Team1HalfTimeScore = HalfTimeScore ? HalfTimeScore[0] : null;
    const Team2HalfTimeScore = HalfTimeScore ? HalfTimeScore[2] : null;

    const Team1FullTimeScore = FullTimeScore ? FullTimeScore[0] : null;
    const Team1ExtraTimeScore = ExtraTimeScore ? ExtraTimeScore[0] : null;

    const Team2FullTimeScore = FullTimeScore ? FullTimeScore[2] : null;
    const Team2ExtraTimeScore = ExtraTimeScore ? ExtraTimeScore[2] : null;
      
    const exisitng_match = await match.findOne({
      where: {
        StaticID: StaticID,
      },
    });
  
    // const exisitng_match = null;
    if (exisitng_match) {
      exisitng_match.MatchDate = MatchDate;
      exisitng_match.Status = matches["@status"];
      exisitng_match.Team1Score = matches.localteam["@goals"];
      exisitng_match.Team1FullTimeScore = Team1FullTimeScore;
      exisitng_match.Team1ExtraTimeScore = Team1ExtraTimeScore;
      exisitng_match.Team1HalfTimeScore = Team1HalfTimeScore;
      exisitng_match.Team1PenaltyScore = Team1PenaltyScore;

      exisitng_match.Team2Score = matches.visitorteam["@goals"];
      exisitng_match.Team2FullTimeScore = Team2FullTimeScore;
      exisitng_match.Team2ExtraTimeScore = Team2ExtraTimeScore;
      exisitng_match.Team2HalfTimeScore = Team2HalfTimeScore;
      exisitng_match.Team2PenaltyScore = Team2PenaltyScore;
      exisitng_match.updatedAt = new Date().toISOString();
      // console.log("exx")
      try {
        console.log("start",new Date().toISOString()," ",StaticID);
        await exisitng_match.save();
        console.log("end",new Date().toISOString()," ",StaticID);
        console.log("updated");
        return res.json("match updated");
        // console.log(Team1Name, " ", Team2Name, " ", "match updated");
      } catch (error) {
        console.log("match error", error.message);
      }
    } else {
      const postData = {
        MatchID,
        StaticID,
        Season,
        MatchDate,
        Status,
        Week,
        Stage,
        Round,
        TournamentID,
        TournamentName,
        Team1Name,
        Team1ID,
        Team2ID,
        Team2Name,
        Team1Score,
        Team1HalfTimeScore,
        Team1FullTimeScore,
        Team1PenaltyScore,
        Team1ExtraTimeScore,
        Team2Score,
        Team2HalfTimeScore,
        Team2FullTimeScore,
        Team2PenaltyScore,
        Team2ExtraTimeScore,
      };

      try {
        await match.create(postData);
        console.log("match created");
        return res.json("match created");
      } catch (error) {
        console.log("match error", error.message);
      }
    }
  }

  return res.json("done");
};

Sequelize PostgreSQL配置

production: {
    username: "username",
    password: "password",
    database: "db-name",
    host: "rds-url",
    dialect: "postgres",
    port: 5432,
    dialectOptions: {
      connectTimeout: 1000000,
    },
    logging: false,
 },

问题分析与解决方案

1. 冷启动是否是元凶?

你的Lambda初始化时长平均700ms,远低于周六的4145ms延迟,所以冷启动不是主要原因。如果周六调用量远超日常100~150K,可能出现并发冷启动,但结合延迟量级来看,数据库层面的问题概率更高。

2. 数据库读写缓慢的问题

你提到读操作平均5秒,这本身已是高延迟,周六的延迟大概率来自这个读操作瓶颈:

  • 检查StaticID字段是否建索引:无索引时findOne会做全表扫描,周六写入请求增多导致数据量或并发查询量上升,会直接拖慢查询速度。
  • 查看周六RDS监控:重点看CPU使用率、连接数、磁盘IOPS是否超出阈值。连接数爆满会导致请求排队,CPU过高说明数据库负载过重,磁盘IO瓶颈会影响所有读写操作。

3. PostgreSQL配置与Sequelize优化

Sequelize配置调整

  • connectTimeout设置为1000000ms(约16分钟)过大,会导致Lambda等待数据库连接超时的时间过长,建议调整为5000ms左右,避免无效等待占用函数时长。
  • 添加连接池配置:Sequelize默认连接池大小较小,高并发场景下会出现连接等待,建议补充:
    production: {
      // 原有配置保留
      pool: {
        max: 20, // 最大连接数
        min: 5, // 最小空闲连接数
        acquire: 5000, // 获取连接超时时间
        idle: 30000 // 连接空闲超时时间
      }
    }
    

PostgreSQL RDS配置检查

  • 检查实例规格:如果日常刚好满足负载,周六激增时会资源不足,可考虑升级实例规格或开启只读副本分流读请求。
  • 调整数据库参数:shared_buffers、work_mem等参数影响缓存和查询性能,RDS默认配置可能不匹配你的负载,可根据实际情况调整。
  • 开启慢查询日志:定位周六期间的慢SQL,找到具体性能瓶颈语句。

代码优化建议

  • 改用upsert替代findOne+save:Sequelize的upsert方法可自动执行“存在则更新,不存在则插入”,减少一次数据库往返请求:
    await match.upsert({
      StaticID,
      MatchID,
      MatchDate,
      // ...其他需要更新/插入的字段
    });
    
  • 简化日期处理逻辑:合并两次moment调用,减少不必要的计算:
    const MatchDate = moment(
      `${date.split(".").reverse().join(".")} ${req.body["@time"] === "TBA" ? "00:00" : req.body["@time"]}`,
      "YYYY-MM-DD HH:mm:ss"
    );
    
  • 完善错误响应:当前代码中save或create出错时无错误响应,需添加res.status(500).json("操作失败")之类的逻辑,避免请求挂起。

内容的提问来源于stack exchange,提问作者Tapu Das

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:10:14