一个小文件:占用namenode多大内存150字节;
128 * 1024*1024*1024byte/150字节 = 9亿文件块
(1KB(Kilobyte,千字节)=1024B= 2^10 B;1MB(Megabyte,兆字节,百万字节,简称“兆”)=1024KB= 2^20 B;1GB(Gigabyte,吉字节,十亿字2113节,又称“千兆”)=1024MB= 2^30 B。)
(1)采用har归档方式,将小文件归档
我们的hdfs中保存大量小文件(当然不产生小文件是最佳实践),这样会把namenode的namespace搞的很大。namespace保存着hdfs文件的inode信息,文件越多需要的namenode内存越大,但内存毕竟是有限的(这个是目前hadoop的硬伤)。
下面图片展示了,har文档的结构。har文件是通过mapreduce生成的,job结束后源文件不会删除。
(2)采用CombineTextInputFormat
CombineTextInputFormat切片机制优化大量小文件
默认情况下TextInputformat对任务的切片机制是按文件规划切片,不管文件多小,都会有一个单独的切片,都会交给一个maptask,如果有大量的小文件,就会产生大量的maptask,处理效率及其低下优化策略(1) 最好的办法,在数据处理系统的最前端(预处理/采集),将小文件先合并成大文件,再上传到HDFS后续分析
(2)补救措施:如果已经是大量小文件在HDFS中了,可以使用另一种InputFormat来做切片(CombineTextInputFormat),切片逻辑和TextFileInputFormat不同,可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个maptask
(3)优先满足最小切片大小,不超过最大切片大小
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m CombineTextInputFormat.setMinInputSplitSize(job, 2097152);// 2m四个文件 举例:0.5m+1m+0.3m+5m=2m + 4.8m=2m + 4m + 0.8m
具体实现步骤:
如果不设置InputFormat,它默认用的是TextInputFormat.class
job.setInputFormatClass(CombineTextInputFormat.class) CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m CombineTextInputFormat.setMinInputSplitSize(job, 2097152);// 2m
(3)有小文件场景开启JVM重用;如果没有小文件,不要开启JVM重用,因为会一直占用使用到的task卡槽,直到任务完成才释放。JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间
<property> <name>mapreduce.job.jvm.numtasks</name> <value>10</value> <description>How many tasks to run per jvm,if set to -1 ,there is no limit</description> </property>
参考:https://www.iteye.com/blog/heipark-1356063