MR读取大量小文件优化

背景

平台打印的日志是以100M为一个文件,压缩后在10M-20M之间,因此,通过传文件方式到bi的数据,一般一个文件为10M-20M;

通过kafka传输的日志,取决于日志量的大小和sdk活跃的时段,因此对于量小的日志,经常会出现kB级别大小的文件,如下:

mapreduce在处理小文件时,每个小文件都需要创建一个map任务,对于有海量小文件的情况,会创建大量的map任务,对集群资源造成大量的消耗,也给集群带来巨大的压力,频繁的mapTask初始化和创建带来的开销远远高于数据处理本身。就我们目前的情况,经常出现一个任务上万个mapTask的情况,涉及到周聚合或月聚合的情况,mapTask的数量会达到几十万个,给系统带来很大的瞬时压力。

解决方案

mapreduce官方已经提供了CombineTextInputFormat来实现对海量小文件进行优化,通过将大量的小文件聚合在一个mapTask中执行来降低对集群的压力,提高执行效率。同时提供了3个配置参数:

1)mapreduce.input.fileinputformat.split.maxsize:合并为一个split的最大值(单位byte),当超过该值时新建一个split
2)mapreduce.input.fileinputformat.split.minsize.per.node:在第一步合并后每个节点剩余的文件,如果大于该值(单位byte),单独创建一个split
3)mapreduce.input.fileinputformat.split.minsize.per.rack:在第二步处理完,每个机架上剩余的文件,如果大于该值(单位byte),单独创建一个split

解释几点:

1)上面3个参数不用全部配置,默认值都为0,如果3个值都不配置,会将所有的小文件合并为一个split;

2)3个参数配置时,要求:2<3<1,否则程序报错;

3)如果小文件小于mapreduce.input.fileinputformat.split.maxsize,但是一个datanode上面的小文件总大小超过该值,会按照上面1、2、3依次创建split;

3)要特别注意:如果一个datanode上面的所有的小文件加起来还未达到配置的mapreduce.input.fileinputformat.split.maxsize,这时的情况有2种情况:

扫描二维码关注公众号,回复: 2207491 查看本文章

    1.  2)、3)没有配置,这时候是将所有的小文件做合并,并按照mapreduce.input.fileinputformat.split.maxsize值拆分为不同的split

    2.  2)、3)参数配置的情况下,此时第二个参数生效,会将每个节点上面的文件(第一步剩余的),作为一个split

4)3个参数要合理配置,某些情况下执行效率可能会降低,因为不合理的合并会破坏mapTask的本地化,可能带来额外的网络开销

5)将大量小文件合并到一个mapTask中,总的执行时间未必为减少(并行度降低了),但对系统资源的消耗一般来说肯定是减少了很多

结合当前架构所需改造

1)创建job时,只需要将TextInputFormat替换为:org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat

2)在map时,获取每条数据所在文件名的方法发生了变化,我已经把获取方法封装在MapperUtils类中(在gx-axe-lib-hadoop-api工程中),如下:

3)在任务提交脚本中增加如下3个参数(推荐配置)

-Dmapreduce.input.fileinputformat.split.maxsize=67108864 -Dmapreduce.input.fileinputformat.split.minsize.per.node=1024 -Dmapreduce.input.fileinputformat.split.minsize.per.rack=1024 

mapreduce.input.fileinputformat.split.maxsize配置128M,后面参数是为了避免一个节点上所有的小文件总大小还未达到mapreduce.input.fileinputformat.split.maxsize时,会被合并为一个split,从而执行效率低下的问题。

这3个参数最好结合实际的数据进行测试调整。

优化后效果

为了检验优化后的效果,特地写了一个测试mapreduce程序,下面是优化前后对比:

1)优化前,一个小文件一个mapTask,如下:

2)优化后,只有75个mapTask了:

对比可以发现,优化后不但map数量减少了很多,单个mapTask的平均执行时间反而变短了,总的资源开销比原来少了很多。

猜你喜欢

转载自blog.csdn.net/mnasd/article/details/80980125