Java 17 Lambda写入JSON到S3时CloudWatch指标丢失问题
问题描述
我用Java 17开发了一个AWS Lambda函数,触发条件是当JSON文件上传到指定S3存储桶时执行。上传的JSON包含DynamoDB、RDS等AWS资源名称,Lambda会拉取这些资源的CloudWatch指标,整合到新的JSON对象中,最后将这个JSON写入文件并上传到另一个S3桶。
目前遇到的诡异问题:
- 执行写入+上传S3的操作时,最终生成的JSON完全没有指标数据
- 但只要注释掉写入和上传的代码,控制台打印的JSON就包含完整的指标数据
- 试过两种上传方式:临时文件写入后上传、直接字节流上传,结果完全一致
- 进一步排查发现:仅注释掉
s3.putObject这一行,打印的JSON就有指标;取消注释,指标就丢失,而且指标拉取的逻辑本身是正常的。
可能的原因及解决办法
1. JSON序列化时机或线程安全问题
如果你的JSON对象使用了非线程安全的集合(比如普通HashMap)存储指标,或者在调用s3.putObject时才进行序列化,可能因为IO操作的并发特性导致数据未被正确写入。
解决步骤:
- 先完成JSON序列化,生成字节数组或字符串,再执行上传操作,避免上传时才序列化:
// 提前完成序列化,确保数据已固化 ObjectMapper objectMapper = new ObjectMapper(); byte[] jsonData = objectMapper.writeValueAsBytes(yourMetricJsonObj); // 再上传到S3 s3.putObject(PutObjectRequest.builder() .bucket("target-bucket-name") .key("output.json") .contentType("application/json") .build(), RequestBody.fromBytes(jsonData));
- 确保存储指标的集合是线程安全的,比如用
Collections.synchronizedMap()包装,或者在序列化前拷贝到新的不可变对象中。
2. Lambda执行生命周期导致的资源中断
Lambda的执行环境可能因为IO操作耗时,提前回收了某些资源,比如后台异步的指标拉取任务未完成就被终止。
解决步骤:
- 确认所有指标拉取操作都是同步执行的,如果用了
CompletableFuture这类异步工具,必须调用join()或get()等待所有任务完成后再处理上传。 - 在序列化前加一次日志打印,确认JSON对象里已经包含指标数据,再执行上传。
3. 上传前意外修改了JSON对象
检查代码中是否有逻辑在调用s3.putObject前,清空或修改了JSON对象的指标字段,比如某些清理代码误删了数据。
解决步骤:
- 在上传前做一次数据校验,比如打印JSON字符串,或者将其写入Lambda临时目录(
/tmp)查看内容,确认数据完整性。 - 排查是否有全局变量或共享对象被意外修改,尽量使用局部变量存储生成的JSON对象。
4. S3上传的元数据或权限问题
虽然概率低,但权限不足或元数据错误也可能导致文件内容异常。
解决步骤:
- 检查Lambda执行角色是否拥有目标S3桶的
s3:PutObject权限。 - 上传时显式指定
Content-Type: application/json,避免S3默认编码导致内容解析异常(如上述代码示例)。
内容的提问来源于stack exchange,提问作者davidb
相关产品推荐
相关产品推荐

