小文件治理:合并与参数控制
小文件过多的直接后果是任务变慢、元数据服务承压:每个文件都要打开并读取元信息,扫描开销远高于数据本身。治理顺序是先控制写入端的产生源(分区数、reduce 数、流式小批次提交),再在读取端合并输入缓解查询压力,最后对存量表做定期合并重写。
基本信息
| 产生原因 | 分区多、reduce 多、流式小批次写入 |
|---|---|
| 写入端控制 | 控制并发与单文件大小 |
| 读取端缓解 | 合并输入参数 |
| 存量治理 | 定期合并重写任务 |
| 观察指标 | 分区文件数与平均文件大小 |
典型使用场景
- 新任务上线:按目标文件大小设置写出并行度,从源头避免小文件
- 读取端临时缓解:开启输入合并,让小文件在一次 map 里合并读取
- 存量表治理:按周对高分区数表做合并重写,而不是每天全量重写
- 流式写入:降低提交频率,或开启引擎自带的小文件自动合并能力
- 根因排查:先定位产生源(哪个任务、哪些分区),再决定治理手段
参数控制示例
参数控制示例
-- 读取端:合并小文件输入,减少 map 任务数
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
set mapred.max.split.size=134217728; -- 单个 split 约 128MB
-- 写入端:任务结束时自动合并小文件
set hive.merge.mapfiles=true; -- map-only 任务结束后合并
set hive.merge.mapredfiles=true; -- map-reduce 任务结束后合并
set hive.merge.size.per.task=268435456; -- 每个合并任务目标 256MB
set hive.merge.smallfiles.avgsize=16777216; -- 平均小于 16MB 时触发合并治理手段与作用位置
| 手段 | 作用位置 | 效果 |
|---|---|---|
| 控制写出并行度 | 写入端 | 从源头减少小文件 |
| 自动合并参数 | 写入端 | 任务结束即合并 |
| 输入合并读取 | 读取端 | 缓解查询扫描开销 |
| 定期合并重写 | 存量治理 | 收敛历史小文件 |
合并任务本身消耗资源,按周对高分区数表执行即可;每天全量重写会把资源消耗变成常态,与生产跑批抢占集群。
只在读取端合并而不治理写入端,新数据仍持续产生小文件,问题会反复出现,治理成本被摊到每一次查询上。