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. BaseAdapter以及对ListView的优化(转)

    背景 对于ListView.GridView.Gallery.Spinner等等,它是它们的适配器,直接继承自接口类Adapter的,使用BaseAdapter时需要重写很多方法,其中最重要的当属ge ...

  2. HDU 2639 (01背包第k优解)

    /* 01背包第k优解问题 f[i][j][k] 前i个物品体积为j的第k优解 对于每次的ij状态 记下之前的两种状态 i-1 j-w[i] (选i) i-1 j (不选i) 分别k个 然后归并排序并 ...

  3. 【开源java游戏框架libgdx专题】-12-开发工具-图片合成

    TexturePackerGui工具: 1.工具使用: 首先看到texturepacker的界面 界面介绍: New pack:创建项目按钮,单击后输入文件名称,创建文件. Input directo ...

  4. HDU5308-脑补-对拍

    先贴上对拍的结果: 感想:可以明显发现下标相差1的关系,所以对付这种需要大量脑补的水题,真的蛋疼,以前没用过对拍,只知道有这么回事,调程序什么的都是手算,人工模拟(经常大脑发热,严重缺氧不足),所以试 ...

  5. request.getAttribute( "result");和request.setAttribute("result",username);

    request.setAttribute("result",username);在request对象中加入名为result的属性并附值为username,因为request对象是可 ...

  6. Hibernate 性能优化之一级缓存

     1.一级缓存的生命周期     一级缓存在session中存放,只要打开session,一级缓存就存在了,当session关闭的时候,一级缓存就不存在了   2.一级缓存是依赖于谁存在的      ...

  7. ubuntu下apache与php配置

    实验环境 uname -a Linux tomato 4.4.0-34-generic #53-Ubuntu SMP Wed Jul 27 16:06:39 UTC 2016 x86_64 x86_6 ...

  8. Tweet button with a callback – How to?

    原文: http://jaspreetchahal.org/tweet-button-with-a-callback-how-to/ 两种方式:1. 原生的button <a href=&quo ...

  9. C++在使用Qt中SLOT宏需要注意的一个小细节

    大家都知道C++虚函数的机制,对于基类定义为虚函数的地方,子类如果覆写,在基类指针或者引用来指向子类的时候会实现动态绑定. 但如果指针去调用非虚函数,这个时候会调用C++的静态绑定,去判断当前的指针是 ...

  10. linux下 oracle常用命令

    打开图形化窗口: 1)Database Configuration Assistant windows    (添加数据库实例) $ dbca 2)Oracle Net Configuration A ...