我在HDFS目录中有一堆小文件。尽管文件的体积相对较小,但每个文件的处理时间是巨大的。也就是说,64mb
文件(TextInputFormat
的默认拆分大小)甚至需要几个小时才能处理。
我需要做的是减少拆分大小,这样我就可以为一项工作使用更多的节点。
所以问题是,怎么可能通过10kb
来分割文件呢?为此,我是否需要实现自己的InputFormat
和RecordReader
,或者是否需要设置任何参数?谢谢
可以为每个作业单独设置的参数mapred.max.split.size
就是您想要的。不要更改dfs.block.size
,因为这是HDFS的全局设置,可能会导致问题。
Hadoop最终指南,第203页"最大拆分大小默认为Java long类型可以表示的最大值。只有当它小于块大小时才有效果,强制拆分小于块。拆分大小由以下公式计算:
max(minimumSize, min(maximumSize, blockSize))
默认情况下
minimumSize < blockSize < maximumSize
因此拆分大小为blockSize
例如,
Minimum Split Size 1
Maximum Split Size 32mb
Block Size 64mb
Split Size 32mb
Hadoop处理少量大文件比处理大量小文件效果更好。其中一个原因是FileInputFormat以这样一种方式生成拆分,即每个拆分都是单个文件的全部或部分。如果文件非常小("小"意味着比HDFS块小得多),并且有很多输入,那么每个映射任务将处理非常少的输入,并且会有很多输入(每个文件一个),每一个都会带来额外的记账开销。将一个1gb的文件分成16个64mb的块,与10000个左右100kb的文件进行比较。10000个文件各使用一个地图,作业时间可能比具有单个输入文件和16个地图任务的等效文件慢几十倍或数百倍。
这里有一个片段,它说明了在没有神奇配置字符串的情况下完成所需操作的正确方法。所需的常量在FileInputFormat
中定义。如果需要,可以从默认的HDFS块常量中获取块大小,但它很有可能是用户定义的。
在这里,如果定义了最大分割大小,我只需将其除以2。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
// ....
final long DEFAULT_SPLIT_SIZE = 128 * 1024 * 1024;
final Configuration conf = ...
// We need to lower input block size by factor of two.
conf.setLong(
FileInputFormat.SPLIT_MAXSIZE,
conf.getLong(
FileInputFormat.SPLIT_MAXSIZE, DEFAULT_SPLIT_SIZE) / 2);
编写一个自定义输入格式,该格式扩展了combinefileinputformat[在hadoop发行版上有自己的优点和缺点]。它将输入拆分合并为mapred.max.split.size 中指定的值