AWS S3桶通知Lambda报NoSuchKey异常求助
AWS Lambda读取DataBrew写入S3的文件报404 NoSuchKey问题解决
问题原因
你遇到的问题源于AWS Glue DataBrew的文件写入机制:DataBrew向S3输出文件时,会先创建带.temp后缀的临时文件,待文件完全写入完成后,再原子性地将临时文件重命名为最终目标文件。而S3的PutObject事件通知会在临时文件上传完成时就触发Lambda,此时要么临时文件已被DataBrew删除/重命名,要么还处于未完全就绪状态,导致Lambda调用getObject时返回404 NoSuchKey。
手动上传文件无此问题,是因为手动上传直接写入最终文件,没有临时文件的中间步骤。
解决方案
1. 在Lambda代码中过滤临时文件
直接在代码里判断文件后缀,跳过.temp结尾的文件,只处理最终目标文件:
S3EventNotification.S3EventNotificationRecord record = event.getRecords().get(0); String s3Bucket = record.getS3().getBucket().getName(); String s3Key= record.getS3().getObject().getUrlDecodedKey(); // 跳过DataBrew的临时文件 if (s3Key.endsWith(".temp")) { return; } // 正常读取文件逻辑 try { S3Object s3object = s3Client.getObject(s3Bucket , s3Key); // 后续处理逻辑 } catch (AmazonS3Exception e) { // 异常处理 }
2. 在S3事件通知中添加过滤规则
直接在S3的事件通知配置里设置过滤条件,只对最终文件的Put事件触发Lambda:
- 进入S3存储桶的「属性」→「事件通知」
- 编辑现有通知规则,在「过滤条件」中添加后缀过滤,填写你的DataBrew输出文件后缀(如
.csv、.parquet) - 这样只有符合后缀的最终文件上传时才会触发Lambda,
.temp文件的Put事件会被直接忽略
3. 添加重试机制(备选方案)
如果担心文件重命名的原子性延迟,可以给getObject操作添加指数退避的重试逻辑,应对短暂的文件不可用情况:
S3EventNotification.S3EventNotificationRecord record = event.getRecords().get(0); String s3Bucket = record.getS3().getBucket().getName(); String s3Key= record.getS3().getObject().getUrlDecodedKey(); int maxRetries = 3; long baseDelay = 1000; // 初始延迟1秒 S3Object s3object = null; for (int retry = 0; retry < maxRetries; retry++) { try { s3object = s3Client.getObject(s3Bucket, s3Key); break; } catch (AmazonS3Exception e) { if (e.getStatusCode() == 404 && retry < maxRetries - 1) { try { Thread.sleep(baseDelay * (long) Math.pow(2, retry)); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException("重试被中断", ie); } } else { throw e; } } } // 处理s3object
最佳实践
优先使用方案1或方案2过滤临时文件,因为DataBrew的.temp文件属于中间产物,本身不需要被处理。重试机制仅作为备选,用于处理极少数的原子重命名延迟场景。
内容的提问来源于stack exchange,提问作者handle_009
相关产品推荐
相关产品推荐

