问题背景
很多客⼾在⽣产环境都会遇到⼩⽂件问题,⼩⽂件可能来⾃于上游系统,可能来⾃于书写不当的sql,也可能是错误数据导致join ⽣成⼤量⼩⽂件。 ⽤⼾侧观察到的现象就是,性能下降,任务报错,甚⾄executor lost。
问题分析
⼩⽂件问题隐患:
1. 导致map 任务⾮常多,从而性能下降;
2. ⼩⽂件过多,可能会影响到后续reduce任务数量暴增,从⽽导致出现task 超过10w的情况,这时候引擎会出于⾃我保护会报错;
3. ⼩⽂件如果⾮常⼩,在进⾏automerge后,还可能导致executor端,每个task需要读太多⼩⽂件,从⽽会在⼀个task中new 过多DFSClient,DFSInputStream,Path,JobConf对象等,导致 executor端内存和gc 压⼒很⼤,甚⾄executor lost。
排查思路
⼀般来说,⼀个任务是由⼏个步骤组成的,⽽⼩⽂件的产⽣也来⾃任务的各个流程和步骤:
上游 => 本地⽂件系统 => HDFS => Map => Reduce => FileSink
所以解决⼩⽂件问题就是从上⾯步骤中⼊⼿,并且解决⼩⽂件的隐患越早越好,跟过滤下推⼀样,能尽早做的过滤条件⼀定是尽早过滤。 能在本地⽂件系统解决的问题,没必要放到HDFS上解决,因为HDFS本⾝就不适合存储⼤量⼩⽂件,⼩⽂件过多会导致namenode元数据特别⼤, 占⽤太多内存,严重影响HDFS的性能。
解决方案
5. maptask阶段合并:automerge
Automerge⽤法及注意事项:https://community.transwarp.cn/thread?topicId=250
改进partition automerge:https://community.transwarp.cn/thread?topicId=251
7. filesink合并:
⼩⽂件合并改进:https://community.transwarp.cn/thread?topicId=253
⼩⽂件合并设计实现版本:https://community.transwarp.cn/thread?topicId=252
操作实例
某⽤⼾上游应⽤产⽣了57000 个⼩⽂件,每个⽂件⼀⾏数据。创建text 外表后,执⾏任务报了task 超过10w。 第⼀反应先⾛automerge,开启automerge后,数据本地合并后⼤概合并了出了不到10 个task,然后就把executor 跑lost了。
问题是每个任务需要读的⽂件太多了,⼀个task中连续new DFSClient,DFSInputStream,Path,JobConf 等对象,导致gc压⼒太⼤,最后executor lost。
最终解决⽅案是:
1. 尽量在本地⽂件系统上合并
2. 本地⽂件系统如果不能合并,在hdfs 上使⽤append file 合并
3. 如果不能在local filesystem或者hdfs合并,考虑创建中间表,通过reduce task + distribute by来降低⽂件数量