AWS Glue ETL作业写入S3过慢问题排查:动态数据框与S3均分区
核心原因:大量小文件导致的S3写入开销
你的写入耗时过长,本质是生成了过多的极小文件(300KB)。S3的每个文件写入都包含固定的HTTP请求开销、元数据更新开销,当总文件数达到量级后,这些开销会被大幅放大,远远超过实际数据写入的时间。结合你的代码和场景,具体诱因如下:
分区键过多(5个)
5个分区键会导致分区目录数量呈指数级增长(比如每个键有10个不同值,总分区数可达10^5=100,000个)。每个分区下再生成40个小文件,总文件数会达到数百万级别,这直接触发了大量的S3写入请求,累积的开销拖慢了整体速度。文件合并配置不足
你仅设置了groupFiles": "inPartition",这个参数仅控制在分区内合并文件,但没有指定合并后的目标文件大小(groupSize)。Glue默认不会主动将小文件合并到合理尺寸(通常Parquet文件建议128MB-256MB),因此每个分区内依然生成了大量300KB的小文件。作业并行度与数据分布不匹配
处理阶段的并行度较高(能快速处理1GB数据),但每个并行任务处理的数据量过小,写入时直接生成了对应数量的小文件。而groupFiles的合并逻辑没有抵消这种高并行度带来的小文件问题。
针对性解决方案
1. 补充文件大小合并配置
在connection_options中添加groupSize参数,指定每个Parquet文件的目标大小(单位:字节),让Glue在分区内自动合并小文件到合理尺寸。例如设置为128MB:
bucket_s3_final = glueContext.write_dynamic_frame.from_options( frame=df, connection_type="s3", connection_options={ "path": "s3://my_bucket/", "partitionKeys": ['col1', 'col2', 'col3', 'col4', 'col5'], "groupFiles": "inPartition", "groupSize": "134217728" # 128MB,按需调整为256MB(268435456) }, format="parquet", )
2. 精简分区键
评估5个分区键的必要性,去掉非必需的键。分区键过多不仅会导致写入慢,还会严重影响后续查询的性能(需要遍历大量分区目录)。如果业务上必须保留所有分区键,建议先评估各键的基数,优先保留基数低、查询频率高的键。
3. 调整作业并行度或预分区数据
- 调整Glue作业参数:通过
--num-workers和--worker-type降低并行度,比如使用G.2Xworker类型,减少worker数量,让每个worker处理更多数据,从源头减少小文件生成。 - 写入前重分区:对DynamicFrame进行重分区,减少总分区数,再执行写入:
from awsglue.dynamicframe import DynamicFrame # 根据分区键重分区,或直接指定分区数 repartitioned_df = df.repartition(['col1', 'col2', 'col3', 'col4', 'col5']) # 或直接指定分区数量,例如coalesce减少分区数 # repartitioned_df = df.coalesce(100) bucket_s3_final = glueContext.write_dynamic_frame.from_options( frame=repartitioned_df, connection_type="s3", connection_options={ "path": "s3://my_bucket/", "partitionKeys": ['col1', 'col2', 'col3', 'col4', 'col5'], "groupFiles": "inPartition", "groupSize": "134217728" }, format="parquet", )
4. 启用Glue性能优化
在Glue作业的设置中开启Optimize Performance选项,Glue会自动优化数据分区和文件大小,减少小文件生成,同时提升写入效率。
内容的提问来源于stack exchange,提问作者Joao Donasolo

