Hadoop权威指南(第三版)P31

Hadoop divides the input to a MapReduce job into fixed-size pieces called input
splits, or just splits. Hadoop creates one map task for each split, which runs the userdefined
map function for each record in the split.
Having many splits means the time taken to process each split is small compared to the
time to process the whole input. So if we are processing the splits in parallel, the processing
is better load-balanced if the splits are small, since a faster machine will be able
to process proportionally more splits over the course of the job than a slower machine.
Even if the machines are identical, failed processes or other jobs running concurrently
make load balancing desirable, and the quality of the load balancing increases as the
splits become more fine-grained.
On the other hand, if splits are too small, then the overhead of managing the splits and
of map task creation begins to dominate the total job execution time. For most jobs, a
good split size tends to be the size of an HDFS block, 64 MB by default, although this
can be changed for the cluster (for all newly created files), or specified when each file
is created.
Hadoop does its best to run the map task on a node where the input data resides in
HDFS. This is called the data locality optimization since it doesn’t use valuable cluster
bandwidth. Sometimes, however, all three nodes hosting the HDFS block replicas for
a map task’s input split are running other map tasks so the job scheduler will look for
a free map slot on a node in the same rack as one of the blocks. Very occasionally even
this is not possible, so an off-rack node is used, which results in an inter-rack network
transfer. The three possibilities are illustrated in Figure 2-2.

It should now be clear why the optimal split size is the same as the block size: it is the
largest size of input that can be guaranteed to be stored on a single node. If the split
spanned two blocks, it would be unlikely that any HDFS node stored both blocks, 
so
some of the split would have to be transferred across the network to the node running
the map task, which is clearly less efficient than running the whole map task using local
data.

============================================================================

Hadoop权威指南(第三版)P47

HDFS blocks are large compared to disk blocks, and the reason is to minimize the cost
of seeks. By making a block large enough, the time to transfer the data from the disk
can be made to be significantly larger than the time to seek to the start of the block.
Thus the time to transfer a large file made of multiple blocks operates at the disk transfer
rate.
A quick calculation shows that if the seek time is around 10 ms, and the transfer rate
is 100 MB/s, then to make the seek time 1% of the transfer time, we need to make the
block size around 100 MB. The default is actually 64 MB, although many HDFS installations
use 128 MB blocks. This figure will continue to be revised upward as transfer
speeds grow with new generations of disk drives.
This argument shouldn’t be taken too far, however. Map tasks in MapReduce normally
operate on one block at a time, so if you have too few tasks (fewer than nodes in the
cluster), your jobs will run slower than they could otherwise.

============================================================================

Hadoop是怎么分块的

hadoop的分块有两部分,其中第一部分更为人熟知一点。
 
第一部分就是数据的划分(即把File划分成Block),这个是物理上真真实实的进行了划分,数据文件上传到HDFS里的时候,需要划分成一块一块,每块的大小由hadoop-default.xml里配置选项进行划分。
 
<property>
  <name>dfs.block.size</name>
  <value>67108864</value>
  <description>The default block size for new files.</description>
</property>
 
这个就是默认的每个块64MB。
数据划分的时候有冗余,个数是由
<property>
  <name>dfs.replication</name>
  <value>3</value>
  <description>Default block replication. 
  The actual number of replications can be specified when the file is created.
  The default is used if replication is not specified in create time.
  </description>
</property>
指定的。
 
具体的物理划分步骤要看Namenode,这里要说的是更有意思的hadoop中的第二种划分。
 
在hadoop中第二种划分是由InputFormat这个接口来定义的,其中有个getSplits方法。这里就有了一个新的不为人熟知的概念:Split。Split的作用是什么,Split和Block是什么关系,下面就可以说明清楚。
在Hadoop0.1中,split划分是在JobTracker端完成的,发生在JobInitThread对JobInProgress调用inittasks()的时候;而在0.18.3中是由JobClient完成的,JobClient划分好后,把split.file写入hdfs里,到时候jobtracker端只需要读这个文件,就知道Split是怎么划分的了。
第二种划分只是一种逻辑上划分,目的是为了让Map Task更好的获取数据输入,仔细分析如下这个场景:
 
File 1 : Block11, Block 12, Block 13, Block 14, Block 15
File 2 : Block21, Block 22, Block 23
 
File1有5个Block,最后一个Block当然可能小于64MB;File2有3个Block
 
如果用户在程序中指定map tasks的个数,比如说是2(如果不指定的话maptasks个数默认是1),那么在
FileInputFormat(最常见的InputFormat实现)的getSplits方法中,首先会计算totalSize=8(可以对照源码看看,注意getSplits这个函数里的计量单位是Block个数,而不是Byte个数,后面有个变量叫bytesremaining仍然表示剩余的Block个数,有些变量名让人无语),然后会计算goalSize=totalSize/numSplits=4,对于File1,计算一个Split有多少个Block是这样计算的
 
long splitSize = computeSplitSize(goalSize, minSize, blockSize);
protected long computeSplitSize(long goalSize, long minSize, long blockSize) {
 return Math.max(minSize, Math.min(goalSize, blockSize));
}
这里minSize是1(说明了一个Split至少包含一个Block,不会出现一个Split包含零点几个Block的情况),计算得出splitSize=4,所以接下来Split划分是这样分的:
Split 1: Block11, Block12, Block13,Block14
Split 2: Block15
Split 3: Block21, Block22, Block23
那用户指定的map个数是2,出现了三个split怎么办?在JobInProgress里其实maptasks的个数是根据Splits的长度来指定的,所以用户指定的map个数只是个参考。可以参看JobInProgress: initTasks()
里的代码:
 
  try {
   splits = JobClient.readSplitFile(splitFile);
  } finally {
   splitFile.close();
  }
  numMapTasks = splits.length;
  maps = new TaskInProgress[numMapTasks];
 
所以问题就很清晰了,还如果用户指定了20个map作业,那么最后会有8个Split(每个Split一个Block),所以最后实际上就有8个MapTasks,也就是说maptask的个数是由splits的长度决定的。
 
几个简单的结论:
1. 一个split不会包含零点几或者几点几个Block,一定是包含大于等于1个整数个Block
2. 一个split不会包含两个File的Block,不会跨越File边界
3. split和Block的关系是一对多的关系
4. maptasks的个数最终决定于splits的长度
 
 
还有一点需要说明,在FileSplit类中,有一项是private String[] hosts;
看上去是说明这个FileSplit是放在哪些机器上的,实际上hosts里只是存储了一个Block的冗余机器列表。
比如上面例子中的Split 1: Block11, Block12, Block13,Block14,这个FileSplit中的hosts里最终存储的是Block11本身和其冗余所在的机器列表,也就是说Block12,Block13,Block14存在哪些机器上没有在FileSplit中记录。
 
FileSplit中的这个属性有利于调度作业时候的数据本地性问题。如果一个tasktracker前来索取task,jobtracker就会找个task给他,找到一个maptask,得先看这个task的输入的FileSplit里hosts是否包含tasktracker所在机器,也就是判断和该tasktracker同时存在一个机器上的datanode是否拥有FileSplit中某个Block的备份。
 
但总之,只能牵就一个Block,其他Block就从网络上传罢。

===========================================================================

hadoop的分块有两部分。

第一部分就是数据的划分(即把File划分成Block),这个是物理上的划分,数据文件上传到HDFS里的时候,需要划分成一块一块,每块的大小由hadoop-default.xml里配置选项进行划分(大小不足一块时,便按实际大小存放):

<property>

<name>dfs.block.size</name>

<value>67108864</value>

<description>The default block size for new files.</description></property>

这里设置的是每个块64MB。
数据划分的时候也可以设置备份的份数:
<property>

<name>dfs.replication</name>

<value>3</value>

<description>Default block replication.   The actual number of replications can be specified when the file is created.  The default is used if replication is not specified in create time.  </description>

</property>
具体的物理划分步骤由Namenode决定,下面hadoop中的第二种划分,用来决定M/R运行时,一个map处理的数据量。

在hadoop中第二种划分是由InputFormat这个接口来定义的,其中有个getSplits方法。这里有一个新的概念:fileSplit。每个map处理一个fileSplit,所以有多少个fileSplit就有多少个map(map数并不是单纯的由用户设置决定的)。

我们来看一下hadoop分配splits的源码:

if ((length != 0) && isSplitable(fs, path)) {

long blockSize = file.getBlockSize();

long splitSize = computeSplitSize(goalSize, minSize, blockSize);

long bytesRemaining = length;

while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {

int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);

splits.add(new FileSplit(path, length-bytesRemaining, splitSize, blkLocations[blkIndex].getHosts()));

bytesRemaining -= splitSize;        }

if (bytesRemaining != 0) {

splits.add(new FileSplit(path, length-bytesRemaining, bytesRemaining,  blkLocations[blkLocations.length-1].getHosts()));        }

} else if (length != 0) {

splits.add(new FileSplit(path, 0, length,blkLocations[0].getHosts()));

} else {

//Create empty hosts array for zero length files

splits.add(new FileSplit(path, 0, length, new String[0]));

}

}

从代码可以看出,一个块为一个splits,即一个map,只要搞清楚一个块的大小,就能计算出运行时的map数。而一个split的大小是由goalSize, minSize, blockSize这三个值决定的。computeSplitSize的逻辑是,先从goalSize和blockSize两个值中选出最小的那个(比如一般不设置map数,这时blockSize为当前文件的块size,而goalSize是文件大小除以用户设置的map数得到的,如果没设置的话,默认是1),在默认的大多数情况下,blockSize比较小。然后再取bloceSize和minSize中最大的那个。而minSize如果不通过”mapred.min.split.size”设置的话(”mapred.min.split.size”默认为0),minSize为1,这样得出的一个splits的size就是blockSize,即一个块一个map,有多少块就有多少map。

上面说的是splitable的情况,unsplitable可以根据实际情况来计算,一般为一个文件一个map。

下面是摘自网上的一个总结:

几个简单的结论:
1. 一个split不会包含零点几或者几点几个Block,一定是包含大于等于1个整数个Block
2. 一个split不会包含两个File的Block,不会跨越File边界
3. split和Block的关系是一对多的关系
4. maptasks的个数最终决定于splits的长度

还有一点需要说明,在FileSplit类中,有一项是private String[] hosts;
看上去是说明这个FileSplit是放在哪些机器上的,实际上hosts里只是存储了一个Block的冗余机器列表。
比如有个fileSplit 有4个block: Block11, Block12, Block13,Block14,这个FileSplit中的hosts里最终存储的是Block11本身和其备份所在的机器列表,也就是说 Block12,Block13,Block14存在哪些机器上没有在FileSplit中记录。

FileSplit中的这个属性有利于调度作业时候的数据本地性问题。如果一个tasktracker前来索取task,jobtracker就会找个 task给他,找到一个maptask,得先看这个task的输入的FileSplit里hosts是否包含tasktracker所在机器,也就是判断 和该tasktracker同时存在一个机器上的datanode是否拥有FileSplit中某个Block的备份。

但总之,只能牵就一个Block,其他Block就要从网络上传。不过对于默认大多数情况下的一个block对应一个map,可以通过修改hosts使map的本地化数更多一些。 在讲block的hosts传给fileSplit时,hosts中的主机地址可以有多个,表示map可以从优先从这些hosts中选取(只是优先,但hdfs还很可能根据当时的网络负载选择不是hosts中的主机起map task)。

知道这个特性之后,可以修改传回给fileSplit的hosts,在列表中只写block所在的那些hosts,这样hdfs就会优先将这些map放到这些hosts上去执行,由于hosts上有该block,就省掉了网络传输数据的时间。

这样做的话,在job很多的时候,可能会出现hot spot,即数据用的越多,它所在hosts上的map task就会越多。所以在考虑修改传给fileSplit的时候要考虑平衡诸多因素

hadoop block split 区别相关推荐

  1. 考究Hadoop中split的计算方法

    Hadoop中block块大小和split切片大小会影响到MapReduce程序在运行过程中的效率.map的个数.在本文中,以经典入门案例WordCount为例,通过debug的方式跟踪源代码,来分析 ...

  2. Spark精华问答 | Spark和Hadoop的架构区别解读

    总的来说,Spark采用更先进的架构,使得灵活性.易用性.性能等方面都比Hadoop更有优势,有取代Hadoop的趋势,但其稳定性有待进一步提高.我总结,具体表现在如下几个方面. 1 Q:Spark和 ...

  3. slice,splice,split区别和作用

    slice,splice,split区别和作用 slice(start,[end])方法:该方法是对数组进行部分截取,该方法返回一个新数组,参数start是截取的开始数组索引,end参数等于你要取的最 ...

  4. mtd block device和block device区别,MTD设备的一般不宜挂载fat,ext2,ext3等文件系统原因

    文章系转载:https://dolaameng328.iteye.com/blog/1502547 本文添加自己理解: 1.可以解释为什么MTD设备的一般不宜挂载fat,ext2,ext3等文件系统- ...

  5. mysql索引如何分裂节点_Oracle索引分裂(Index Block Split)

    索引分裂:index  block split :就是索引块的分裂,当一次DML 事务操作修改了索引块上的数据,但是旧有的索引块没有足够的空间去容纳新修改的数据,那么将分裂出一个新的索引块,旧有块的部 ...

  6. inline, block, inline-block区别

    inline, block, inline-block区别 inline Not height and width; Not margin-top & margin-bottom; Alway ...

  7. subString与split区别

    最近在写项目的时候涉及到了字符串的切割,开始自己使用的时候没有怎么放在心上,但是当我用split来切割这个点号的时候,发现切割不了,获取的是空数组(split要想对点进行切割得加转义字符),所以就去特 ...

  8. Hadoop中Block和Split区别

    两者是从不同的角度来定义的: HDFS以固定大小的block为基本单位存储数据(分布式文件系统,实际存储角度,物理存储单位): MapReduce以split作为处理单位(编程模型角度,逻辑单位): ...

  9. Storm精华问答 | storm与Hadoop有什么区别?

    戳蓝字"CSDN云计算"关注我们哦! 归于Apache社区,Storm被业界称为实时版Hadoop.随着越来越多的场景对Hadoop的MapReduce高延迟无法容忍.而目前已是分 ...

最新文章

  1. forEach和for in
  2. 搜索Maven依赖资源_搜索Maven工件_搜索Maven构件_搜索依赖_搜索构件_搜索工件
  3. 3.2 读入两个参数
  4. 大流量场景下如何云淡风轻地进行线上发布?
  5. 网络里有陌生计算机,怎样使用陌生电脑安全上网
  6. Ubuntu 通过Deb 安装 MySQL 5.5 [转载]
  7. nginx 在阿里云怎么安装mysql_在阿里云 CentOS 服务器(ECS)上搭建 nginx + mysql + php-fpm 环境...
  8. 2018年AI和ML(NLP,计算机视觉,强化学习)技术概述和2019年趋势
  9. android系统签名
  10. 基于springBoot的社区信息管理系统
  11. html分行分列代码,表格内如何强制换行 选中单元格后,点击数据中的分列
  12. TurboMail邮件系统图片签名档功能
  13. Libcurl最初的实现tfp上传和下载功能
  14. Iphone的Wallet中如何移除电子登机牌凭证
  15. php随机生成昵称,使用PHP批量生成随机用户名
  16. lisp语言cond和if套用_方案 – if和cond之间的区别?
  17. “AI+机器人”持续为多领域增“智”添“质”,开启效益增长飞轮
  18. 用python可以做什么有趣的事情_用python做一些有趣的事(一)——根据照片制作版画...
  19. 前端HTML5+CSS3学习笔记
  20. 英读廊——拔了电源插头为什么要等三十秒再重插?

热门文章

  1. linux磁盘爆满问题排查
  2. STCP与TCP协议
  3. SRS 简单高效的实时视频服务器
  4. Android中自动拦截电话
  5. mysql中的my.cnf_在mysql中更改默认的my.cnf路径
  6. SnnGrow快讯:微软 Win7/8.1 今日结束支持,不会再获得安全更新、AI工程化进程加速,人工智能需要怎样的数据?
  7. 文件生成过程编译过程
  8. 启动vfloppy.sys错误
  9. ceph rbd mysql_ceph的rbd使用和理解(全)
  10. ORACLE ERP的词汇表(ZT)