Hadoop适用于少量的大文件场景,而不是大量的小文件场景(这里的小文件通常指文件大小显著小于HDFS Block Size的文件),其主要原因是因为FileInputFormat在为这些小文件生成切片的时候,会为每一个小文件生成一个切片,如果小文件数目众多,会导致大量的Map Task,每个Map Task仅仅处理很少量的数据(即一个小文件的全部数据),这种情况会带来很大的运行开销且耗时较长。
 
CombineFileInputFormat设计目的就是用来应对小文件的场景,FileInputFormat为每一个小文件生成一个切片,而CombineFileInputFormat会将许多小文件“打包”为一个切片,使得每一个Map Task可以处理更多的数据。更为关键的是CombineFileInputFormat在决定将哪些小文件的数据块“打包”为一个切片时会充分考虑数据本地性(节点本地性、机器本地性)的特性,因此不会在运行时间和网络带宽方面来很大的开销。
 
不光是小文件的场景,在处理大文件时CombineFileInputFormat也有优势,原因在于它会将同一节点上的多个数据块形成一个切片,对Data-Local Map Tasks可能带来一定的优化。
 
思路
 
CombineFileInputFormat有三个重要的属性:
 
 
maxSplitSize:切片大小最大值,可通过属性mapreduce.input.fileinputformat.split.maxsize或CombineFileInputFormat实例方法setMaxSplitSize()进行设置;
 
minSplitSizeNode:同一节点的数据块形成切片时,切片大小的最小值,可通过属性mapreduce.input.fileinputformat.split.minsize.per.node或CombineFileInputFormat实例方法setMinSplitSizeNode()进行设置;
 
minSplitSizeRack:同一机架的数据块形成切片时,切片大小的最小值,可通过属性mapreduce.input.fileinputformat.split.minsize.per.rack或CombineFileInputFormat实例方法setMinSplitSizeRack()进行设置;
 
 
CombineFileInputFormat有一个“过滤池”的概念,pools中保存着多个“过滤池”实例(实际就是MultiPathFilter实例,该实例由多个PathFilter实例构成),一个切片中的数据块只可能来自于同一个过滤池,但可以来自同一个过滤池中的不同文件。
 
注:“过滤池”的设计目的还不是很明白,欢迎大家交流,貌似Hive有相关的应用。
 
getSplits():
 
 
step 1
 
获取输入路径中的所有文件;
 
step 2
 
迭代为每个过滤池中的文件生成切片;
 
     step 2.1
     
     获取满足当前过滤池实例的所有文件myPaths;
 
     step 2.2
 
     为mypaths中的文件生成切片;
 
step 3
 
为不属于任何过滤池的文件生成切片。
 
无论是满足某过滤池实例条件的文件还是不属于任何过滤池的文件,可以笼统地理解为“一批文件”,getMoreSplits()就是为这一批文件生成切片的。
 
 
step 1
 
前面提到,CombineFileInputFormat在将小文件“打包”为一个切片的时候,会考虑数据本地性(节点本地性、数据本地性),而且一个切片涉及到多个小文件,因此此处定义了三个对应关系:
 
rackToBlocks:机架和数据块的对应关系;
blockToNodes:数据块和节点的对应关系;
nodeToBlocks:节点和数据块的对应关系。
 
此外还应注意到比较重要的两个类:
 
OneFileInfo:代表一个文件;
OneBlockInfo:代表一个文件中的数据块,注意这个地方的数据块是“逻辑”上的数据块,不能直接对应HDFS Block,后续会说原因。
 
step 2
 
迭代这“一批文件”,为每一个文件构建OneFileInfo对象(由OneFileInfo构造函数完成),OneFileInfo对象本身并没有多少实际作用,它的意义是在构建过程中维护了上述三个对应关系的信息。
 
其中有一段代码是为这个文件生成对应的OneBlockInfo对象(多个),如下:
 
 
可以看出,对于每一个数据块(由locations[i]表示)而言,构建OneBlockInfo的逻辑是一个循环的过程,根据maxSize(maxSplitSize)的值不同就有可以产生多个OneBlockInfo对象,这也是“逻辑块”的原因。
 
迭代完成之后,我们即可以认为数据块、节点、机架相互之间的对应关系已经建立完毕,接下来可以根据这些信息生成切片。
 
step 3 
 
切片的形成过程(createSplits())如下:
 
(1)不断迭代节点列表,逐个节点(数据块)形成切片(Local Split);对于每一个节点而言,遍历并累加这个节点上的数据块,
     a.如果maxSplitSize != 0且累加的数据块大小大于或等于maxSize,则将这些数据块形成一个切片,继续下一个节点(为了达到多个节点之间分布切片的目的);
     b.如果maxSplitSize == 0,则上述累加的数据块可能为该节点的全部数据块,也可能是节点在迭代过程中剩余的数据块,这些数据块根据条件的不同可能全部形成一个切片,或者全部留作后续处理;
 
(2)不断迭代机架列表,逐个机架(数据块)形成切片(Rack Split);对于每一个机架而言,处理流程与(1)类同,仅判断条件时策略不同;
     
(3)遍历并累加剩余数据块,如果maxSplitSize != 0且累积的数据块大小大于或等于maxSplitSize,则将这些数据块形成一个切片;
 
(4)剩余数据块形成一个切片。
 
该部分代码比较冗长,建议读者自行阅读,核心逻辑比较简单:优先将一个节点上的数据块形成切片(同时兼顾切片分布问题),次之将一个机架的数据块形成切片,最后将剩余数据块形成切片。

Hadoop CombineFileInputFormat实现原理及源码分析的更多相关文章

  1. Hadoop FileInputFormat实现原理及源码分析

    FileInputFormat(org.apache.hadoop.mapreduce.lib.input.FileInputFormat)是专门针对文件类型的数据源而设计的,也是一个抽象类,它提供两 ...

  2. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  3. ConcurrentHashMap实现原理及源码分析

    ConcurrentHashMap实现原理 ConcurrentHashMap源码分析 总结 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对Ha ...

  4. HashMap和ConcurrentHashMap实现原理及源码分析

    HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...

  5. (转)ReentrantLock实现原理及源码分析

    背景:ReetrantLock底层是基于AQS实现的(CAS+CHL),有公平和非公平两种区别. 这种底层机制,很有必要通过跟踪源码来进行分析. 参考 ReentrantLock实现原理及源码分析 源 ...

  6. 【转】HashMap实现原理及源码分析

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景极其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...

  7. 【OpenCV】SIFT原理与源码分析:DoG尺度空间构造

    原文地址:http://blog.csdn.net/xiaowei_cqu/article/details/8067881 尺度空间理论   自然界中的物体随着观测尺度不同有不同的表现形态.例如我们形 ...

  8. 《深入探索Netty原理及源码分析》文集小结

    <深入探索Netty原理及源码分析>文集小结 https://www.jianshu.com/p/239a196152de

  9. HashMap实现原理及源码分析之JDK8

    继续上回HashMap的学习 HashMap实现原理及源码分析之JDK7 转载 Java8源码-HashMap  基于JDK8的HashMap源码解析  [jdk1.8]HashMap源码分析 一.H ...

随机推荐

  1. Linux在山Windows共享文件夹

    $ sudo mount.cifs //windows-ip/shared  /media/ -o user=username password=password 该命令挂载Windows在下面sha ...

  2. 使用python求字符串或文件的MD5

    使用python求字符串或文件的MD5 五月 21st, 2008 #以下可在python3000运行. #字符串md5,用你的字符串代替'字符串'中的内容. import hashlib md5=h ...

  3. 移动端屏幕自适应js与rem

    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;&qu ...

  4. dedecms网站文章标题与简标题的调用问题

    使用dedecms调用标签的时候,既然有,咱们就合理利用,如果没有,咱也可以自己去添加.以下介绍dedecms网站文章标题调用的一些技巧,希望大家能够合理运用. dedecms网站文章标题与简标题的调 ...

  5. .net处理页面的抓取数据

    //要抓取数据的页面路径 string url = "http://www.scedu.net/banshi/used-car/lower-secondary-education/middl ...

  6. jquery val() and text().

    .val() works on input elements (or any element with a value attribute?) and .text() will not work on ...

  7. ASP.NET 开发学习视频教程大全(共800集)

      ASP.NET是微软.NET平台的支柱之一,被广泛应用在WEB等互联网开发领域,因此它的强大性和适应性,可以使它运行在Web应用软件开发者的几乎全部的平台上.这里整理了最全的ASP.NET开发学习 ...

  8. Delphi 串口通信(1)

    利用 Delphi实现串口通信的常用的方法有 3种: 一是利用控件,如 MSCOMM控件和 SPCOMM控件: 二是使用 API函数: 三是调用其他串口通信程序.其中利用 API编写串口通信程序较为复 ...

  9. [C++] 对象地址与接口指针的故事

    刚想到一个问题,一直在思考C++中对象地址与接口指针的故事. 问题:多继承的情况下,一个具体类对象实现了多个接口,那么多该对象获取的不同接口指针是一样的吗?不是一样吗?不是对象地址吗?-- 困惑原因, ...

  10. 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object

    有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...