凌晨两点,内部群弹出一条消息:"订阅数据已经两天没更新了。"两个负责统计的Lambda函数——calculateSubscriptionStats和calculatePartnerNotificationStats——原本只是慢,现在彻底停摆了。CloudWatch日志显示,它们反复撞向Lambda的15分钟硬上限(900,000毫秒),中途被强制终止,偶尔还会触发内存溢出错误。
问题比表面更严重。每次运行都卡在900,000毫秒这道红线,作业不是慢,是正在死亡。由于中途崩溃,下游数据要么过时,要么残缺。数据量持续增长,系统终于越过了悬崖。
![]()
排查后发现三个相互叠加的瓶颈。第一层:全量下载模式。DynamoDB访问层每次返回完整行数据,但高流量表(Addon、Bundle、Partner Notifications)里70%的字节都是下游用不到的字段——oldData、newData、嵌套的审计元数据。DynamoDB单页硬限制1MB,无效字段挤占空间,导致更多分页、更多网络往返、更多JSON解析开销,最终堆内存爆炸。
第二层:每日全表重算。calculatePartnerNotificationStats每次调用都扫描整张表,重新计算uniqueCustomers和monthlyCounts等累计指标。1万行时没问题,百万行且日增时,昨天的数据要连带着之前所有天数再读一遍——永无止境。
第三层:状态无持久化。累计值只在Lambda内存中维护,没有"上一状态"概念。Lambda既是计算节点又是唯一数据源,一旦崩溃,数字就错到下次成功运行为止。
修复分三层推进。第一层全面推行ProjectionExpression,只取必要字段,单页有效数据量提升3倍以上,网络往返和解析开销骤降。这是成本最低的突破口,也为后续改造腾出空间。
第二层引入增量计算架构。不再每日全表扫描,改为基于时间窗口的增量处理,新数据追加更新,历史结果持久化存储。累计指标从"重新发明"变成"接力传递",计算量与当日新增数据成正比,与历史总量脱钩。
第三层将状态外迁。累计值写入持久化存储,Lambda变为无状态纯计算节点。崩溃后可从断点恢复,下游数据可靠性不再绑定于单次运行的生死。
最终效果:同一作业从15分钟超时边缘降至亚秒级完成。更深层的变化是架构认知——Lambda不是数据库,不该承载状态;DynamoDB不是文件系统,扫描操作需要被敬畏。当数据规模跨越临界点,"能跑"和"能活"是完全不同的工程标准。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.