小文件相关问题的处理思路

友情链接


问题背景

很多客⼾在⽣产环境都会遇到小文件问题,小文件可能来⾃于上游系统,可能来⾃于书写不当的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的性能。

方案

  1. 上游系统改进
  2. linux文件系统合并上游系统改进
  3. hdfs 合并:hdfs dfs -appendToFile a.txt b.txt c.txt hdfs://${namenode}/data/all.txt
  4. 存储端合并(不同表格式采用不同的compact机制,具体可参考小文件详解文章
  5. maptask阶段合并:使用automerge功能(使用方法具体可参考小文件详解文章中计算端合并的章节内容)
  6. reduce 阶段合并:reduce tasks 设置,mapred.reduce.tasks,如果没有sql本来没有reduce,可以加上:distribute by rand();(具体设置值可参考小文件详解文章中计算端合并的章节内容)
  7. 设置合理的分区和分桶,过多的分桶,或者不合理的分区,可能导致分区和分桶比较多,小文件++
  8. 数据正确性检查,有时候是数据错误导致生成了过多小文件。

实例

某用户,上游应用产生了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来降低文件数量


评论
登录后可评论
发布者
星小环分享号
文章
180
问答
205
关注者
27
banner
关注星环科技
获取最新活动资讯

加入TDH社区版技术交流群

获取更多技术支持 ->

扫描二维码,立即加入