小文件处理专题
一 MapReduce
1.1 小数据带来的问题
- 在HDFS上,每个文件在NameNode上占150Byte(在内存中占用),如果小文件过多的话就占用大量的Namenode内存,并且查找元数据的速度会很慢
- 在处理MapReduce的过程中每一个小文件就要启动切一片,并且要启动一个maptask,每个maptask默认内存是1G,这样会大量消耗NodeManager内存,同时一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。
1.2 如何解决
-
从数据源头解决,如果是在flume传输数据进入HDFS的时候控制文件滚动参数,或者使用hbase数据库存储流失数据进行定期合并
## 不要产生大量小文件(滚动策略,按照时间滚动,文件大小滚动,数据条数) a1.sinks.k1.hdfs.rollInterval = 3600 a1.sinks.k1.hdfs.rollSize = 134217728 a1.sinks.k1.hdfs.rollCount = 0
-
存储在hdfs上可以通过har归档的方式合并小文件,但是只能解决NameNode内存问题,对于MapReduce 来说起不到任何作用,因为har文件就相当一个目录,仍然不能讲小文件合并到一个split中去,一个小文件一个split ,任然是低效的
-
MR时:
-
MR输入时可以使用combineinputformat的方式通过设置合并小文件的大小
// 如果不设置InputFormat,它默认用的是TextInputFormat.class job.setInputFormatClass(CombineTextInputFormat.class); //虚拟存储切片最大值设置4m CombineTextInputFormat.setMaxInputSplitSize(job, 134217728);
-
开启uber模式,实现jvm重用,默认每个task任务占用一个jvm,使用完之后就会释放,其他task需要重新申请,如果task结束不释放jvm,让另一个task继续使用,就会节省task申请jvm的时间
https://blog.csdn.net/myproudcodelife/article/details/44477819 uber模式,jvm使用详解,1.X支持重用,2.X支持uber
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>
**弊端:**开启JVM重用时,task用过的插槽会一直被占用,直到整个查询任务结束,插槽才会被释放
-
调优,不仅仅是叫理解调优之后的值,调优是遇到一些特殊场景再调优,一般情况是采用默认值,参数调优就是把默认值改了,默认值就是应对大部分场景下的情况,调优应对的是特殊情况。
-
二 hive
2.1 hive小文件是如何产生的
- 动态分区:hive支持的动态分区功能很强大,可以根据字段自动分区,但是如果分区字段的数值种类过多的话就会在hdfs产生很多的小文件,导致hive在MR的时候处理过多的小文件
- reduce过多,每一个reducetask默认输出一个文件
- 数据源本身就含有大量小文件
2.2 小文件的危害:
同hadoop的MR一样
2.2 如何解决
-
使用Hadoop achieve把小文件进行归档
-
重建表,建表时减少reduce的数量(也就是减少分区数的产生)
distribute by 字段名,cast(rand(),123) --重建表
-
在hive程序运行之前设置参数合并小文件
//每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
- 设置map输出和reduce输出进行合并的相关参数调整map和reduce的数量
//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000
三 spark
-
spark处理小文件:
主要是通过repartition和coalesce减少分区达到处理小文件的效果
- repartition默认使用shuffle,一般使用这种
- coalesce默认使用不使用shuffle,有可能会产生数据倾斜
-
sparkSQL设置reduce的读取目标数据量
val sc = new SparkContext(conf) val hiveContext = new HiveContext(sc) --启用Adaptive Execution,从而启用自动设置Shuffle hiveContext.setConf("spark.sql.adaptive.enabled","true") --设置每个Reducer读取的目标数据量,默认64M,一般改成集群块大小 hiveContext.setConf("spark.sql.adaptive.shuffle.targetPostShuffleInputSize","128000000")
-
https://blog.csdn.net/a13705510005/article/details/102295768 spark具体的小文件场景以及解决办法
-
算子也可以调整分区