小文件处理专题
Hadoop 小文件优化方法
2.3.1 Hadoop小文件弊端
HDFS上每个文件都要在NameNode中都有对应的元数据,这个元数据的大小约为150byte,这样当小文件比较多的时候,一方面会大量占用NameNode的内存空间,另一方面就是元数据过多的情况查找速度变慢。
小文件过多,在进行MR计算时,会导致生成过多的切片. 需要启动过多的MapTask。
1.3.2 Hadoop小文件解决方案
1)小文件优化的方向:
(1)在数据采集的时候,就将小文件或小批数据合成大文件再上传HDFS。
## 不要产生大量小文件(滚动策略,按照时间滚动,文件大小滚动,数据条数)
a1.sinks.k1.hdfs.rollInterval = 3600
a1.sinks.k1.hdfs.rollSize = 134217728
a1.sinks.k1.hdfs.rollCount = 0
(2)在业务处理之前,在HDFS上使用MapReduce程序对小文件进行合并。
读取的是小文件(1000个),输出是大文件,设置reduce的数量少一点(正常值),这一步是还是很慢
(3)在MapReduce处理时,可采用CombineTextInputFormat提高效率。
// 如果不设置InputFormat,它默认用的是TextInputFormat.class
job.setInputFormatClass(CombineTextInputFormat.class);
//虚拟存储切片最大值设置4m
CombineTextInputFormat.setMaxInputSplitSize(job, 134217728);
(4)开启uber模式,实现jvm重用
2)Hadoop Archive
是一个高效的将小文件放入HDFS块中的文件存档工具,能够将多个小文件打包成一个HAR文件,从而达到减少NameNode的内存使用
小文件存档
3.案例实操
(1)需要启动YARN进程
[bigdata@hadoop102 hadoop-2.7.2]$ start-yarn.sh
(2)归档文件
把/user/bigdata/input目录里面的所有文件归档成一个叫input.har的归档文件,并把归档后文件存储到/user/bigdata/output路径下。
[bigdata@hadoop102 hadoop-2.7.2]$ bin/hadoop archive -archiveName input.har –p /user/bigdata/input /user/bigdata/output
(3)查看归档
[bigdata@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr /user/bigdata/output/input.har
[bigdata@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr har:///user/bigdata/output/input.har
(4)解归档文件
[bigdata@hadoop102 hadoop-2.7.2]$ hadoop fs -cp har:/// user/bigdata/output/input.har/* /user/bigdata
3)SequenceFile
SequenceFile是由一系列的二进制k/v组成,如果为key为文件名,value为文件内容,可将大批小文件合并成一个大文件
4)CombineTextInputFormat
CombineTextInputFormat用于将多个小文件在切片过程中生成一个单独的切片或者少量的切片。
5)开启uber模式,实现jvm重用。默认情况下,每个Task任务都需要启动一个jvm来运行,如果Task任务计算的数据量很小,我们可以让同一个Job的多个Task运行在一个Jvm中,不必为每个Task都开启一个Jvm.
开启uber模式,在mapred-site.xml中添加如下配置
<!-- 开启uber模式 -->
<property>
<name>mapreduce.job.ubertask.enable</name>
<value>true</value>
</property>
<!-- uber模式中最大的mapTask数量,可向下修改 -->
<property>
<name>mapreduce.job.ubertask.maxmaps</name>
<value>9</value>
</property>
<!-- uber模式中最大的reduce数量,可向下修改 -->
<property>
<name>mapreduce.job.ubertask.maxreduces</name>
<value>1</value>
</property>
<!-- uber模式中最大的输入数据量,如果不配置,则使用dfs.blocksize 的值,可向下修改 -->
<property>
<name>mapreduce.job.ubertask.maxbytes</name>
<value></value>
</property>
6)配置mapreduce.job.jvm.numtasks 参数实现在一个Jvm中运行多个Task . 如果设置为-1 ,
则没有数量限制。 一般设置在 10-20之间.
有小文件场景开启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>
调优,不仅仅是叫理解调优之后的值,调优是遇到一些特殊场景再调优,一般情况是采用默认值,参数调优就是把默认值改了,默认值就是应对大部分场景下的情况,调优应对的是特殊情况。
补充:
1. hive的小文件如何处理
7)小文件如何产生的?
(1)动态分区插入数据(如果动态分区的字段设置不合理,有的时候你会 发现明知道不合理,但是你必须这样设置),分区数太多,产生大量的小文件,导致map数量剧增;
(2)reduce数量越多,小文件也越多(reduce的个数和输出文件是对应的);
(3)数据源本身就包含大量的小文件。
8)小文件解决方案
https://blog.csdn.net/shudaqi2010/article/details/90342417
(1)在Map执行前合并小文件,减少Map数:CombineHiveInputFormat具有对小文件进行合并的功能(系统默认的格式)。HiveInputFormat没有对小文件合并功能。
set hive.input.format=org.apache.hadoop.hive.al.io.CombineHiveInputFormat
(2)merge
// 输出合并小文件
SET hive.merge.mapfiles = true; -- 默认true,在map-only任务结束时合并小文件
SET hive.merge.mapredfiles = true; -- 默认false,在map-reduce任务结束时合并小文件
SET hive.merge.size.per.task = 268435456; -- 默认256M
SET hive.merge.smallfiles.avgsize = 16777216; -- 当输出文件的平均大小小于16m该值时,启动一个独立的map-reduce任务进行文件merge
(3)开启JVM重用
JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。
Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间,具体多少需要根据具体业务场景测试得出。默认值是1
<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插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。
set mapreduce.job.jvm.numtasks=10
2. spark如何处理小文件
可以采用上述的思路,除了上述的思路之外,还有一些方法,处理小文件;
SparkRDD
coalesce与repartition 解决小文件问题
repartition(numPartitions: Int)
Ø 返回numPartitions分区个数的新RDD(或DataFrame)。
Ø 可以增加或减少此RDD中的并行性级别,内部使用shuffle来重新分配数据。
Ø 如果要减少partition数量,可考虑使用`coalesce`,这可以避免执行shuffle。
p coalesce(numPartitions: Int, shuffle: Boolean = false)
Ø 1)返回一个新的RDD,该RDD被缩减为`numPartitions`分区。
Ø 2)这导致窄依赖,例如, 如果从1000个分区转到100个分区,则不会有shuffle,而是100个新分区中的每一个都将声明当前分区的10个分区。
Ø 3)如果您正在进行剧烈的合并,例如将numPartitions从1000减少为1,这将会导致计算发生在非
常少的节点上(例如numPartitions = 1的情况下为一个节点)。
4)为了避免这种情况,可以传递shuffle = true,或者直接使用repartition。
这将添加一个shuffle步骤,意味着当前的上游分区将并行执行(无论当前的分区是什么)。
Ø
5)注意:随着shuffle = true,实际上可以合并到更大数量的分区。 如果你有少量的分区,比如
100,那么这很有用,可能有几个分区异常大。 调用coalesce(1000,shuffle = true)将导致
使用hash partitioner分发数据到1000个分区。
SparkSQL
https://blog.csdn.net/lhxsir/article/details/99588064
https://blog.csdn.net/a13705510005/article/details/102295768