使用AWS Glue Spark/Python向S3中Hudi表写入时的异常S3性能下降问题
使用AWS Glue Spark/Python作业将数据写入S3存储桶中的Hudi表时,遇到严重的S3性能下降问题:
- 顺序逐个表写入时,运行正常但耗时很长;
- 并行运行多个作业(每个作业处理单个表)时,大量作业因S3性能限制报错。
原本预期S3按前缀限速,每个Hudi表对应独立文件夹(独立前缀),并行操作不会互相影响,但实际并行时触发了限速,与顺序运行表现差异明显。
Hudi配置
config = { 'className' : 'org.apache.hudi', 'hoodie.datasource.write.storage.type': 'COPY_ON_WRITE', 'hoodie.datasource.hive_sync.use_jdbc': 'false', 'hoodie.datasource.write.precombine.field': 'tx_commit_time', 'path': targetPath, # s3 uri of the hudi table folder 'hoodie.table.name': tableName, 'hoodie.datasource.hive_sync.database': dbName, 'hoodie.datasource.hive_sync.table': tableName, 'hoodie.datasource.hive_sync.enable': 'true', 'hoodie.datasource.write.hive_style_partitioning': 'true', 'hoodie.datasource.write.keygenerator.class': 'org.apache.hudi.keygen.ComplexKeyGenerator', 'hoodie.datasource.write.recordkey.field': hudiPrimaryKey, 'hoodie.datasource.write.partitionpath.field': partitionKeyField, 'hoodie.datasource.hive_sync.partition_extractor_class': 'org.apache.hudi.hive.MultiPartKeysValueExtractor', 'hoodie.datasource.hive_sync.partition_fields': partitionKeyField, 'hoodie.upsert.shuffle.parallelism': 20, 'hoodie.insert.shuffle.parallelism': 20, 'hoodie.datasource.write.operation': 'upsert', 'hoodie.cleaner.policy': 'KEEP_LATEST_FILE_VERSIONS', 'hoodie.cleaner.fileversions.retained': 1, 'hoodie.datasource.write.reconcile.schema': 'true', 'hoodie.index.type': 'GLOBAL_SIMPLE' }
写入操作代码
outputDf.write.format('hudi').options(**config).mode('Append').save()
原因分析
Hudi全局元数据的共享路径竞争
每个表的独立文件夹不代表所有操作都隔离,Hudi的GLOBAL_SIMPLE全局索引、commit元数据、cleaner清理操作会访问桶内共享的元数据路径(如各表.hoodie目录下的全局索引文件、commit日志),并行作业同时对这些路径发起请求,会触发S3的限速。COPY_ON_WRITE的高IO开销
采用COPY_ON_WRITE存储类型时,upsert操作需要重写整个数据文件,并行作业会产生大量文件创建、删除、重命名请求,叠加后的总请求量会超过S3单桶的QPS限制(默认3500次/秒PUT/DELETE类请求,5500次/秒GET类请求)。作业并行度叠加的请求压力
每个作业设置了20的写入并行度,多作业并行时总并发写任务数是20乘以作业数量,大量并发请求直接触达S3单桶的性能上限。
规避方法
调整Hudi索引类型
将hoodie.index.type从GLOBAL_SIMPLE改为BLOOM或BUCKET,避免全局索引带来的跨表元数据竞争。若必须使用全局索引,可启用hoodie.index.global.bloom.enable并调整索引并行度参数,减少元数据操作的并发请求。切换为MERGE_ON_READ存储类型
改用MERGE_ON_READ,upsert仅写入增量日志文件,无需重写全量数据文件,大幅降低S3的IO请求压力。控制作业并行度
- 限制同时运行的Glue作业数量,根据S3单桶QPS上限计算合理并行数(比如单作业产生约20次写请求,并行作业数不超过150,需根据实际请求类型调整)。
- 降低单作业的
hoodie.upsert.shuffle.parallelism和hoodie.insert.shuffle.parallelism值(如调整为10),减少单个作业的并发S3请求。
优化Hudi元数据与清理策略
- 调大
hoodie.cleaner.fileversions.retained值(如改为3),减少cleaner的运行频率和文件删除请求。 - 启用
hoodie.cleaner.async异步清理,避免同步清理时的IO竞争。 - 配置
hoodie.commit.retry.count和hoodie.commit.retry.interval,增加commit操作的重试机制,应对短暂的S3限速。
- 调大
优化S3前缀与分区设计
- 为不同表设置更分散的前缀路径(如
s3://bucket/db1/table1、s3://bucket/db2/table2),进一步分散请求压力。 - 优化分区键设计,让数据分散到更多分区文件夹中,避免单个分区下的文件操作过于集中。
- 为不同表设置更分散的前缀路径(如
内容的提问来源于stack exchange,提问作者Aamit

