一、小文件形成的原因:
(1)动态分区插入数据,产生大量的小文件,从而导致 map 数量剧增;
(2)reduce 数量越多,小文件也越多,reduce 的个数和输出文件个数一致;
(3)数据源本身就是大量小文件;
二、小文件的危害:
(1)在 HDFS 中,每个文件均按块存储,每个文件在 NameNode 中存储大约占 150 个字节,与块大小无关,如果小文件过多,则会耗尽 NameNode 中的大多数内存。
(2)从 Hive 角度看,小文件过多也会影响 MR 的执行任务的数量,一个小文件会开启一个 MapTask,同时一个 map 会开一个 JVM 去执行, 任务过多则会导致频繁的开启关闭,浪费大量的资源,严重影响性能。
三、解决小文件问题常见方法:
解决小文件问题的本质就是将小文件进行合并,可以通过以下几种方式解决小文件问题:
(1)使用 Hadoop Archive(HAR)将小文件进行归档:使用 Hadoop 自带的 HAR 将小文件进行归档,将多个小文件打包成一个 HAR 文件,这样 NameNode 中的元数据也就存储一份。在减少 namenode 内存使用的同时,仍然可以对文件进行透明的访问。
使用 HAR 时需要注意两点:
- 对小文件进行存档后,原文件不会自动被删除,需要用户自己删除;
- 创建 HAR 文件的过程实际上是在运行一个 MapReduce 作业,因而需要有一个 Hadoop 集群运行此命令
此外,HAR 还有一些缺陷:
- 不支持修改,一旦创建,Archives 便不可改变。要增加或移除里面的文件,必须重新创建归档文件。
- 要归档的文件名中不能有空格,否则会抛出异常,可以将空格用其他符号替换。
(2)使用 SequenceFile 合并小文件:可以使用 SequenceFile 格式将大批的小文件合并成一个大文件,再使用 MapReduce 程序进行操作,从而提高系统性能。
(SequenceFile 由一系列二进制 key-value 组成,key 是小文件名,value 是小文件内容,这样就可以将大量小文件合并为一个大文件。)
注意:和 HAR 不同的是,这种方式还支持压缩。该方案对于小文件的存取都是比较自由的,不限制用户和文件的多少,但 SequenceFile 文件不能追加写入,也不能修改,适用于一次性写入大量小文件的操作。
(3)使用 CombineFileInputFormat 合并小文件:在 MR 读取数据时将多个小文件合并成一个文件进行处理,只开启一个 MapTask,提高了任务的执行效率。
(这样就不会因为大量小文件而开启大量的 MapTask,把大量的时间花费在启动和释放 task 上面)
(4)开启 JVM 重用:JVM 重用可以使得 JVM 实例在同一个 job 中重新使用 N 次,提高效率。N 的值可以在 Hadoop 的 mapred-site.xml 中配置。通常在 10-20 之间。
注意:有小文件场景时可以开启 JVM 重用;如果没有产生小文件,不要开启 JVM 重用,因为会一直占用 task 卡槽,直到任务完成才释放。