AvroParquetWriter搭配Hadoop配置做S3 SSE时无法使用多个KMS密钥
问题根因
Hadoop的S3AFileSystem实例默认会按URI、用户身份等维度全局缓存,你第一次初始化writer1时,会基于conf1创建带awsKmsId1配置的S3A文件系统实例并缓存。后续创建writer2时,只要访问的是同区域同桶的S3资源,框架会直接复用之前缓存的文件系统实例,不会读取conf2里的新KMS密钥配置,导致所有文件都用第一个密钥加密。
修复方案
两个方案选一个即可:
- 方案1:禁用S3A文件系统缓存
给每个Configuration实例添加fs.s3a.impl.disable.cache配置为true,强制每次创建新的文件系统实例,读取对应配置里的KMS密钥。 - 方案2:为不同KMS配置设置独立缓存键
如果不想完全禁用缓存,可以给每个不同KMS配置的Configuration设置唯一的fs.s3a.cache.key值,框架会按该键区分缓存实例,不会出现配置串用的问题。
修改后代码示例
Configuration conf1 = new Configuration(); conf1.set("fs.s3a.server-side-encryption.key", awsKmsId1); conf1.set("fs.s3a.server-side-encryption-algorithm", "SSE-KMS"); conf1.set("fs.s3a.connection.ssl.enabled", "true"); conf1.set("fs.s3a.endpoint", s3Endpoint); // 新增配置,禁用当前配置对应的文件系统缓存 conf1.setBoolean("fs.s3a.impl.disable.cache", true); Configuration conf2 = new Configuration(); conf2.set("fs.s3a.server-side-encryption.key", awsKmsId2); conf2.set("fs.s3a.server-side-encryption-algorithm", "SSE-KMS"); conf2.set("fs.s3a.connection.ssl.enabled", "true"); conf2.set("fs.s3a.endpoint", s3Endpoint); // 新增配置,禁用当前配置对应的文件系统缓存 conf2.setBoolean("fs.s3a.impl.disable.cache", true); ParquetWriter<GenericRecord> writer1 = AvroParquetWriter.<GenericRecord>builder(path) .withSchema(parquetSchema) .withConf(conf1) .withWriteMode(ParquetFileWriter.Mode.CREATE) .build(); ParquetWriter<GenericRecord> writer2 = AvroParquetWriter.<GenericRecord>builder(path) .withSchema(parquetSchema) .withConf(conf2) .withWriteMode(ParquetFileWriter.Mode.CREATE) .build();
注意事项
- 禁用缓存会带来极小幅的连接初始化性能开销,在writer实例数量不多的场景下几乎感知不到影响。
- 如果你使用的hadoop-aws版本低于2.8.0,建议先升级到稳定版,避免存在缓存相关的已知bug。
内容的提问来源于stack exchange,提问作者HadoopIsFun
相关产品推荐
相关产品推荐

