FileInputFormat类中split切分算法和host选择算法介绍
来源:互联网 发布:vip影视盒子源码 编辑:程序博客网 时间:2024/04/30 23:57
FileInputFormat类中split切分算法和host选择算法介绍
在hadoop源码的org.apache.hadoop.mapred包中,有个FileInputFormat类,这个类的主要作用是提供统一的getSplits函数。该函数实现中最核心的两个算法是split切分算法 和 host选择算法。1、什么是split?
它是在逻辑上对输入数据进行的分片,并不会在磁盘上将其切分成分片进行存储。每个split都作为一个独立单位分配给一个task去处理(这也是为什么要把输入切分成split的原因)。hadoop中用org.apache.hadoop.mapred.FileSplit类来封装分片,其定义如下(省略了成员方法):
public class FileSplit extends org.apache.hadoop.mapreduce.InputSplit implements InputSplit {
注:FileSplit既继承于InputSplit类,又实现InputSplit接口。没错,在hadoop-1.0.0中,既有InputSplit类,在org.apache.hadoop.mapreduce中;又有InputSplit接口,在org.apache.hadoop.mapred中。
private Path file; //split所在的文件(一个split一定只属于一个文件)
private long start; //split在文件中的起始位置
private long length; //split的长度
private String[] hosts; //split所在的主机名称
......
}2、输入文件、split、block三者的关系。
我们可以用一张图来说明三者之间的关系,如下图:
蓝色部分可以看做是一个输入文件,它被划分成多个block,如:block1,block2,block3,block4,block5,等等,存储在HDFS系统上。每个block在HDFS上有三个备份(算上自己,总共三份),每个备份分布在不同的节点(节点可能是主机、机柜、数据中心)上,图中有5个节点,防止因某个节点宕机而丢失数据。同时,一个文件被分成多个split,如:split1,split2,split3,split4等等。
(1)split是文件在逻辑上的划分,是程序中的一个独立处理单位,每一个split分配给一个task去处理。在实际的存储系统中并没有按split去存储。
(2)block是文件在物理上的划分,HDFS系统上就是按照block来存储的。一个block的多个备份存储在不同的节点上。
(3)一个文件可能被划分成多个split,但一个split只可能属于一个文件(稍后代码中将会讲解)。比如:图中的文件至少包含4个split。
(4)一个split可能包含多个block,但一个block不一定只属于一个split。比如:split1完全包含block1,部分包含block2,;block2一部分属于split1,一部分属于split2.
3、split切分算法
这里的文件切分算法指的是将文件切分成split,不是block。文件切分算法主要用来确定 InputSplit的个数 以及 每个InputSplit对应的数据段。对于每个文件,由以下三个属性值确定其对应的InputSplit的个数。
- goalSize :它是根据用户期望的InputSplit数目计算出来的,即totalSize/numSplits。其中,totalSize为输入文件(可能有多个)总大小;numSplits数用户设定的Map Task个数,默认情况下是1.
- minSize :InputSplit的最小值,由配置参数mapred.min.split.size(在/conf/mapred-site.xml文件中配置)确定,默认是1(字节).
- blockSize : 文件在HDFS中存储的block大小(在/conf/hdfs-site.xml文件中配置),不同文件可能不同,默认是64MB。
那么,splitSize = max{minSize, min{goalSize, blockSize}}. 一旦确定了splitSize值后,文件将被切分成大小为splitSize的InputSplit,最后剩下不足splitSize的数据块单独成为一个InputSplit。下面我们来看看源代码。源代码(Hadoop-1.0.0)在org.apache.hadoop.mapred.FileInputFormat的getSplits方法中。
代码中注释已经很详细了,下面简单说明几点:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
(1)long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits); 根据用户的numSplits个数来确定split的目标大小;
(2)方法computeSplitSize就是用来计算split的最终大小的。
(3)下面这段代码意思是将最后不足splitSize的部分也作为一个分片:
if (bytesRemaining != 0) {//将文件的最后一部分作为一个分片
splits.add(new FileSplit(path, length-bytesRemaining, bytesRemaining,
blkLocations[blkLocations.length-1].getHosts()));
}(4) for (FileStatus file: files) {....},这个for循环,是对每一个文件进行分片,那么就可以保证一个split只属于一个文件,不会属于多个文件。
(5)NetworkTopology clusterMap = new NetworkTopology(); 不晓得为什么要定义这么一个对象。虽然作为参数传递给getSplitHosts方法,但在getSplits方法中,真没看出来它有什么作用。如果getSplitHosts方法要用的话,完全可以放在getSplitHosts中定义,为什么要放在getSplits方法中定义呢?
4、host选择算法
InputSplit的四个成员<file,start,length,hosts>,分别表示InputSplit所在的文件、起始位置、长度及所在的host列表。前三个很容易确定,host列表的选择比较困难。host列表的选择策略直接影响到运行过程中的任务本地性。我们都知道HDFS上的文件是以block存储的,一个文件对应的block可能分布在整个Hadoop集群上,而InputSplit的划分算法可能导致一个InputSplit对应多个block,这些block可能位于不同节点上,这使得Hadoop不可能完全实现数据的本地性。
为此,Hadoop将数据本地性按代价划分成三个等级,分别是:node locality(主机本地性)、rack locality(机柜本地性)、data locality(数据中心本地性)。前两个等级在Hadoop都已实现,数据中心本地性暂时还未实现。在任务调度时,会依次考虑3种节点本地性,优先让空闲资源处理本节点上的数据,如果节点上没有可处理的数据,则处理同一个机柜上的数据,最坏的情况是处理其他机柜上的数据(当然必须在同一数据中心)。
虽然InputSplit对应的bloc可能位于多个节点上,但考虑到任务调度的效率,一般不会将所有节点放入InputSplit的hosts列表中,而是选择包含该InputSplit数据量最大的前几个节点(Hadoop限制最多选择10个,多余的会过滤掉),以作为任务调度时判断任务是否具有本地性的主要凭证。一个简单有效的启发式算法(一种可行的算法,并不是最优的)是:首先按照rack包含的数据量对rack进行排序,然后在同一个rack内按node包含的数据量对node排序,最后取前N个node的host作为InputSplit的hosts列表,这里的N为block副本数。这样,当任务调度器调度Task时,只要将Task调度给位于hosts列表中的节点,就认为该Task满足本地性。
我们来看看源代码。源代码(Hadoop-1.0.0)在org.apache.hadoop.mapred.FileInputFormat的getSplitHosts方法中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 136 237 238
代码中注释已经很详细了,下面简单说明几点:
(1)getBlockIndex(BlockLocation[] blkLocations, long offset)方法,这是获取split所在block的索引号。比如说:在第2节的图中,blkLocations={block1, block2, block3, block4, block5, ...},split2从block2的中间部位开始,所以返回的索引为1,即block2在blkLocations中的下标。
(2)hostsMap用来记录主机的一些信息,比如包含split的字节数;racksMap用来记录机柜的一些信息。在遍历完相应的block之后,hostsMap记录下了包含split数据的主机信息,racksMap记录下了包含split数据的机柜信息,那么这些信息(主要是包含split的字节数)就可以用于之后的排序。
(3)org.apache.hadoop.mapred.FileInputFormat.NodeInfo类(是个内部类)的addValue(...)方法,保证了同一个拓扑中的相同block,只会累加一次包含split的字节数。拓扑可以看做是一个绝对路径,比如:/dog/orange/hostname:port,其中dog为数据中心,orange为机架,hostname为主机名,port为端口号。 对于文件的一个block,可能多个主机上都存储着,因为不同的主机就是不同的拓扑,所以不同主机上的相同block都会参与排序,以选出距离本地最近的一个主机。
(4)identifyHosts(...)方法中,首先按机柜上的字节数(split在此机柜上的数据量)从多到少排序,然后在同一机柜的多个主机上按字节数(split在此主机上的数据量)从多到少排序,依次选出要求个数的主机。标识符done的作用是一旦找到要求个数的主机,立即退出循环。
- FileInputFormat类中split切分算法和host选择算法介绍
- FileInputFormat类中split切分算法和host选择算法介绍
- FileInputFormat类中split切分算法和host选择算法介绍
- 文件的切分split和结合工具cat 介绍
- 数据切分算法实践
- 《算法图解》书摘-算法介绍/选择排序
- 几个基础算法介绍和实现——选择排序
- 继承FileInputFormat类和RecordReader类
- 算法导论,最优钢条切分
- Hadoop 之 文件切分算法
- 直接选择排序算法和冒泡排序算法的介绍及实现
- 切分算法(摘自算法第四版)
- 排序算法Java描述:选择、冒泡、插入、希尔、归并、快速及三向切分快速排序
- JAVA冒泡算法和选择算法代码
- 随机洗牌算法和随机选择算法
- 对比:冒泡算法和选择算法
- 冒泡算法和选择算法源码
- 冒泡排序算法和选择排序算法
- c语言(螺旋矩阵)2017.4.23
- web渗透学习路线
- Sublime Text 3 Mac 常用快捷键
- poj2186Popular Cows_ 强连通分支_缩点tarjan算法
- 十大编程算法
- FileInputFormat类中split切分算法和host选择算法介绍
- bzoj1014 火星人prefix 字符串hash + 区间splay树
- C 语言中操作字符串的函数
- Python 多进程
- 算法训练 排序
- 获取文件扩展名(后缀)
- JS断点调试心得
- 接口和抽象类
- wps如何设置表格中文字的行间距