特定时段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
相关产品推荐
相关产品推荐

