Hadoop
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
1 Hadoop常用端口号
hadoop2.x | Hadoop3.x | |
---|---|---|
访问HDFS端口 | 50070 | 9870 |
访问MR执行情况端口 | 8088 | 8088 |
历史服务器 | 19888 | 19888 |
客户端访问集群端口 | 9000 | 8020 |
2 Hadoop配置文件
hadoop2.x core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml slaves
hadoop3.x core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml workers
3 HDFS读流程和写流程
3.1 读
1客户端向namenode请求下载文件namenode通过查询元数据找到文件块所在的datanode地址。
2挑选一台datanode就近原则然后随机服务器请求读取数据。
3datanode开始传输数据给客户端从磁盘里面读取数据放入流以packet为单位来做校验。
4客户端以packet为单位接收先在本地缓存然后写入目标文件。后面的block块Append到前面的block块合成最终文件
3.2 写
1客户端向namenode请求上传文件namenode检查目标文件是否已存在父目录是否存在。
2namenode返回是否可以上传。
3客户端请求第一个 block上传到哪几个datanode服务器上。文件先经过切分处理
4namenode返回3个datanode节点分别为dn1、dn2、dn3。(遵循机架感知原则把副本分别放在不同机架甚至不同数据中心
)
5客户端请求dn1上传数据dn1收到请求会继续调用dn2然后dn2调用dn3将这个通信管道建立完成
6dn1、dn2、dn3逐级应答客户端
7客户端开始往dn1上传第一个block先从磁盘读取数据放到一个本地内存缓存以packet为单位dn1收到一个packet就会传给dn2dn2传给dn3dn1每传一个packet会放入一个应答队列等待应答,当一个block传输完成之后客户端再次请求namenode上传第二个block的服务器。重复执行3-7步。数据传输完成后Datanode会向Client通信同时向Namenode报告存储完成
4 secondary namenode工作机制
1第一阶段namenode启动
1第一次启动namenode格式化后创建fsimage和edits文件。如果不是第一次启动直接加载编辑日志和镜像文件到内存。
2客户端对元数据进行增删改的请求
3namenode记录操作日志更新滚动日志
4namenode在内存中对数据进行增删改查
2第二阶段Secondary NameNode工作
1Secondary NameNode询问namenode是否需要checkpoint。直接带回namenode是否检查结果。
2Secondary NameNode请求执行checkpoint。
3namenode滚动正在写的edits日志
4将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
5Secondary NameNode加载编辑日志和镜像文件到内存并合并。
6生成新的镜像文件fsimage.chkpoint
7拷贝fsimage.chkpoint到namenode
8namenode将fsimage.chkpoint重新命名成fsimage
5 NameNode与SecondaryNameNode 的区别与联系
5.1 区别
1NameNode负责管理整个文件系统的元数据以及每一个路径文件所对应的数据块信息。
2SecondaryNameNode主要用于定期合并命名空间镜像和命名空间镜像的编辑日志。
5.2 联系
1SecondaryNameNode中保存了一份和namenode一致的镜像文件fsimage和编辑日志edits。
2在主namenode发生故障时假设没有及时备份数据可以从SecondaryNameNode恢复数据。
6 hadoop节点动态上线下线怎么操作?
6.1 节点上线操作
当要新上线数据节点的时候需要把数据节点的名字追加在 dfs.hosts 文件中
1关闭新增节点的防火墙
2在 NameNode 节点的 hosts 文件中加入新增数据节点的 hostname
3在每个新增数据节点的 hosts 文件中加入 NameNode 的 hostname
4在 NameNode 节点上增加新增节点的 SSH 免密码登录的操作
5在 NameNode 节点上的 dfs.hosts 中追加上新增节点的 hostname,
6在其他节点上执行刷新操作hdfs dfsadmin -refreshNodes
7在 NameNode 节点上更改 slaves 文件将要上线的数据节点 hostname 追加到 slaves 文件中
8启动 DataNode 节点
9查看 NameNode 的监控页面看是否有新增加的节点
6.2 节点下线操作
1修改/conf/hdfs-site.xml 文件
2确定需要下线的机器dfs.osts.exclude 文件中配置好需要下架的机器这个是阻
止下架的机器去连接 NameNode。
3配置完成之后进行配置的刷新操作./bin/hadoop dfsadmin -refreshNodes,这个操作的作用是在后台进行 block 块的移动。
4当执行三的命令完成之后需要下架的机器就可以关闭了可以查看现在集群上连接的节点正在执行 Decommission会显示Decommission Status : Decommission in progress 执行完毕后会显示Decommission Status : Decommissioned
5机器下线完毕将他们从excludes 文件中移除。
7 HAnamenode 是如何工作的?
ZKFailoverController主要职责
1健康监测周期性的向它监控的NN发送健康探测命令从而来确定某个NameNode是否处于健康状态如果机器宕机心跳失败那么zkfc就会标记它处于一个不健康的状态。
2会话管理如果NN是健康的zkfc就会在zookeeper中保持一个打开的会话如果NameNode同时还是Active状态的那么zkfc还会在Zookeeper中占有一个类型为短暂类型的znode当这个NN挂掉时这个znode将会被删除然后备用的NN将会得到这把锁升级为主NN同时标记状态为Active。
3当宕机的NN新启动时它会再次注册zookeper发现已经有znode锁了便会自动变为Standby状态如此往复循环保证高可靠需要注意目前仅仅支持最多配置2个NN。
4master选举如上所述通过在zookeeper中维持一个短暂类型的znode来实现抢占式的锁机制从而判断那个NameNode为Active状态
8 hadoop2.x Federation
多namespace的方式可以直接减轻单一NameNode的压力。
NameNode共享集群中所有的DataNode它们还是在同一个集群内.
HDFS Federation方案的优势:
第一点,命名空间的扩展
。因为随着集群使用时间的加长HDFS上存放的数据也将会越来越多。这个时候如果还是将所有的数据都往一个NameNode上存放,这个文件系统会显得非常的庞大。这时候我们可以进行横向扩展把一些大的目录分离出去.使得每个NameNode下的数据看起来更加的精简。
第二点,性能的提升
.这个也很好理解。当NameNode所持有的数据量达到了一个非常大规模的量级的时候(比如超过1亿个文件)这个时候NameNode的处理效率可能就会有影响它可能比较容易的会陷入一个繁忙的状态。而整个集群将会受限于一个单点NameNode的处理效率,从而影响集群整体的吞吐量。这个时候多NameNode机制显然可以减轻很多这部分的压力。
第三点,资源的隔离
。这一点考虑的就比较深了。通过多个命名空间我们可以将关键数据文件目录移到不同的NameNode上以此不让这些关键数据的读写操作受到其他普通文件读写操作的影响。也就是说这些NameNode将会只处理特定的关键的任务所发来的请求而屏蔽了其他普通任务的文件读写请求以此做到了资源的隔离。千万不要小看这一点当你发现NameNode正在处理某个不良任务的大规模的请求操作导致响应速度极慢时你一定会非常的懊恼。
9 TextInputFormat和KeyValueInputFormat的区别是什么
1相同点
TextInputformat和KeyValueTextInputFormat都继承了FileInputFormat类都是每一行作为一个记录
2区别
TextInputformat将每一行在文件中的起始偏移量作为 key每一行的内容作为value。默认以\n或回车键作为一行记录。
KeyValueTextInputFormat 适合处理输入数据的每一行是两列并用 tab 分离的形式。
10 FileInputFormat源码解析(input.getSplits(job))
1找到你数据存储的目录。
2开始遍历处理规划切片目录下的每一个文件
3遍历第一个文件ss.txt
a获取文件大小fs.sizeOf(ss.txt);
b计算切片大小
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M
c默认情况下切片大小=blocksize
d开始切形成第1个切片ss.txt—0:128M 第2个切片ss.txt—128:256M 第3个切片ss.txt—256M:300M每次切片时都要判断切完剩下的部分是否大于块的1.1倍不大于1.1倍就划分一块切片
e将切片信息写到一个切片规划文件中
f整个切片的核心过程在getSplit()方法中完成。
g数据切片只是在逻辑上对输入数据进行分片并不会再磁盘上将其切分成分片进行存储。InputSplit只记录了分片的元数据信息比如起始位置、长度以及所在的节点列表等。
h注意block是HDFS上物理上存储的存储的数据切片是对数据逻辑上的划分。
4提交切片规划文件到yarn上yarn上的MrAppMaster就可以根据切片规划文件计算开启maptask个数
。
12 job的map和reduce的数量?
12.1 map数量
splitSize=max{minSize,min{maxSize,blockSize}}
map数量由处理的数据分成的block数量决定
default_num = total_size / split_size;
12.2 reduce数量
reduce的数量job.setNumReduceTasks(x);x 为reduce的数量,不设置的话默认为 1。
13 MapTask工作机制
1Read阶段Map Task通过用户编写的RecordReader从输入InputSplit中解析出一个个key/value。
2Map阶段该节点主要是将解析出的key/value交给用户编写map()函数处理并产生一系列新的key/value。
3Collect收集阶段在用户编写map()函数中当数据处理完成后一般会调用OutputCollector.collect()输出结果。在该函数内部它会将生成的key/value分区调用Partitioner并写入一个环形内存缓冲区中。
4Spill阶段即“溢写”当环形缓冲区满后MapReduce会将数据写到本地磁盘上生成一个临时文件。需要注意的是将数据写入本地磁盘之前先要对数据进行一次本地排序并在必要时对数据进行合并、压缩等操作
。
溢写阶段详情
步骤1利用快速排序算法对缓存区内的数据进行排序排序方式是先按照分区编号partition进行排序然后按照key进行排序。
这样经过排序后数据以分区为单位聚集在一起且同一分区内所有数据按照key有序。
步骤2按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.outN表示当前溢写次数中。如果用户设置了Combiner则写入文件之前对每个分区中的数据进行一次聚集操作。
步骤3将分区数据的元信息写到内存索引数据结构SpillRecord中其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存索引大小超过1MB则将内存索引写到文件output/spillN.out.index中。
5Combine阶段当所有数据处理完成后MapTask对所有临时文件进行一次合并(多路归并算法
)以确保最终只会生成一个数据文件。
当所有数据处理完后MapTask会将所有临时文件合并成一个大文件并保存到文件output/file.out中同时生成相应的索引文件output/file.out.index。
在进行文件合并过程中MapTask以分区为单位进行合并。对于某个分区它将采用多轮递归合并的方式。每轮合并io.sort.factor默认100个文件并将产生的文件重新加入待合并列表中对文件排序后重复以上过程直到最终得到一个大文件。
让每个MapTask最终只生成一个数据文件可避免同时打开大量文件和同时读取大量小文件产生的随机读取带来的开销。
14 ReduceTask工作机制
1Copy阶段ReduceTask从各个MapTask上远程拷贝一片数据并针对某一片数据如果其大小超过一定阈值则写到磁盘上否则直接放到内存中。
2Merge阶段在远程拷贝数据的同时ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并合并同一个分区号的数据
以防止内存使用过多或磁盘上文件过多。
3Sort阶段按照MapReduce语义用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起Hadoop采用了基于排序的策略。由于各个MapTask已经实现对自己的处理结果进行了局部排序因此ReduceTask只需对所有数据进行一次归并排序即可。
4Reduce阶段reduce()函数将计算结果写到HDFS上。
15 mapReduce有几种排序及排序发生的阶段
15.1 排序的分类
1部分排序
MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部排序。
2全排序
如何用Hadoop产生一个全局排序的文件最简单的方法是使用一个分区。但该方法在处理大型文件时效率极低因为一台机器必须处理所有输出文件从而完全丧失了MapReduce所提供的并行架构。
替代方案首先创建一系列排好序的文件其次串联这些文件最后生成一个全局排序的文件。主要思路是使用一个分区来描述输出的全局排序。例如可以为待分析文件创建3个分区在第一分区中记录的单词首字母a-g第二分区记录单词首字母h-n, 第三分区记录单词首字母o-z。
3辅助排序GroupingComparator分组
Mapreduce框架在记录到达reducer之前按键对记录排序但键所对应的值并没有被排序。甚至在不同的执行轮次中这些值的排序也不固定因为它们来自不同的map任务且这些map任务在不同轮次中完成时间各不相同。一般来说大多数MapReduce程序会避免让reduce函数依赖于值的排序。但是有时也需要通过特定的方法对键进行排序和分组等以实现对值的排序。
4二次排序
在自定义排序过程中如果compareTo中的判断条件为两个即为二次排序。
15.2 自定义排序WritableComparable
bean对象实现WritableComparable接口重写compareTo方法就可以实现排序
@Override
public int compareTo(FlowBean o) {
// 倒序排列从大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}
15.3 排序发生的阶段
1一个是在map side发生在spill后partition前。
2一个是在reduce side发生在copy后 reduce前。
16 mapReduce中combiner的作用是什么一般使用情景哪些情况不需要及和reduce的区别
1Combiner的意义就是对每一个maptask的输出进行局部汇总以减小网络传输量
。
2Combiner能够应用的前提是不能影响最终的业务逻辑
而且Combiner的输出kv应该跟reducer的输入kv类型要对应起来。
3Combiner和reducer的区别在于运行的位置:
Combiner是在每一个maptask所在的节点运行
。
Reducer是接收全局所有Mapper的输出结果
。
17 Yarn提交任务流程
18 HDFS的数据压缩算法
Hadoop中常用的压缩算法有bzip2、gzip、lzo、snappy其中lzo、snappy需要操作系统安装native库才可以支持。企业开发用的比较多的是snappy
19 Hadoop的调度器总结
1FIFO
先按照作业的优先级高低再按照到达时间的先后选择被执行的作业。
2计算能力调度器Capacity Scheduler
支持多个队列每个队列可配置一定的资源量每个队列采用FIFO调度策略为了防止同一个用户的作业独占队列中的资源该调度器会对同一用户提交的作业所占资源量进行限定。调度时首先按以下策略选择一个合适队列计算每个队列中正在运行的任务数与其应该分得的计算资源之间的比值选择一个该比值最小的队列然后按以下策略选择该队列中一个作业按照作业优先级和提交时间顺序选择同时考虑用户资源量限制和内存限制
。
3公平调度器Fair Scheduler
同计算能力调度器类似(缺额
)支持多队列多用户每个队列中的资源量可以配置同一队列中的作业公平共享队列中所有资源具体算法参见我的博文《Hadoop公平调度器算法解析》
实际上Hadoop的调度器远不止以上三种最近出现了很多针对新型应用的Hadoop调度器。
4适用于异构集群的调度器LATE
现有的Hadoop调度器都是建立在同构集群的假设前提下具体假设如下
1集群中各个节点的性能完全一样
2对于reduce task它的三个阶段copy、sort和reduce用时各占1/3
3同一job的同类型的task是一批一批完成的他们用时基本一样。
现有的Hadoop调度器存在较大缺陷主要体现在探测落后任务的算法上如果一个task的进度落后于同类型task进度的20%则把该task当做落后任务(这种任务决定了job的完成时间需尽量缩短它的执行时间)从而为它启动一个备份任务speculative task。如果集群异构的对于同一个task即使是在相同节点上的执行时间也会有较大差别因而在异构集群中很容易产生大量的备份任务。
LATELongest Approximate Time to End参考资料[4]调度器从某种程度上解决了现有调度器的问题它定义三个阈值SpeculativeCap系统中最大同时执行的speculative task数目作者推荐值为总slot数的10%
SlowNodeThreshold作者推荐值为25%得分分数计算方法见论文低于该阈值的node快节点上不会启动speculative taskSlowTaskThreshold作者推荐值为25%当task进度低于同批同类task的平均进度的SlowTaskThreshold时会为该task启动speculative task。它的调度策略是当一个节点出现空闲资源且系统中总的备份任务数小于SpeculativeCap时1如果该节点是慢节点节点得分高于SlowNodeThreshold则忽略这个请求。 2对当前正在运行的task按估算的剩余完成时间排序 3选择剩余完成时间最大且进度低于SlowTaskThreshold的task为该task启动备份任务。
5适用于实时作业的调度器Deadline Scheduler和Constraint-based Scheduler
这种调度器主要用于有时间限制的作业Deadline Job即给作业一个deadline时间让它在该时间内完成。实际上这类调度器分为两种软实时允许作业有一定的超时作业调度器和硬实时作业必须严格按时完成作业调度器。
Deadline Scheduler参考资料[5]主要针对的是软实时作业该调度器根据作业的运行进度和剩余时间动态调整作业获得的资源量以便作业尽可能的在deadline时间内完成。
Constraint-based Scheduler参考资料[6]主要针对的是硬实时作业该调度器根据作业的deadline和当前系统中的实时作业运行情况预测新提交的实时作业能不能在deadline时间内完成如果不能则将作业反馈给用户让他重调整作业的deadline。
20 mapreduce 优化方法
20.1 数据输入
1合并小文件
在执行mr任务前将小文件进行合并大量的小文件会产生大量的map任务增大map任务装载次数而任务的装载比较耗时从而导致 mr 运行较慢。
2采用ConbinFileInputFormat来作为输入解决输入端大量小文件场景
。
20.2 map阶段
1减少spill次数
通过调整io.sort.mb及sort.spill.percent参数值增大触发spill的内存上限减少spill次数从而减少磁盘 IO。
2减少merge次数
通过调整io.sort.factor参数增大merge的文件数目减少merge的次数从而缩短mr处理时间。
3在 map 之后先进行combine处理减少 I/O。
20.3 reduce阶段
1合理设置map和reduce数两个都不能设置太少也不能设置太多。太少会导致task等待延长处理时间太多会导致 map、reduce任务间竞争资源造成处理超时等错误。
2设置map、reduce共存调整slowstart.completedmaps参数使map运行到一定程度后reduce也开始运行减少reduce的等待时间。
3规避使用reduce因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。
4合理设置reduc端的buffer默认情况下数据达到一个阈值的时候buffer中的数据就会写入磁盘然后reduce会从磁盘中获得所有的数据。也就是说buffer和reduce是没有直接关联的中间多个一个写磁盘->读磁盘的过程既然有这个弊端那么就可以通过参数来配置使得buffer中的一部分数据可以直接输送到reduce从而减少IO开销mapred.job.reduce.input.buffer.percent默认为0.0。当值大于0的时候会保留指定比例的内存读buffer中的数据直接拿给reduce使用。这样一来设置buffer需要内存读取数据需要内存reduce计算也要内存所以要根据作业的运行情况进行调整。
20.4 IO传输
1采用数据压缩的方式减少网络IO的的时间。安装Snappy和LZOP压缩编码器。
2使用SequenceFile二进制文件
20.5 数据倾斜问题
1数据倾斜现象
数据频率倾斜——某一个区域的数据量要远远大于其他区域。
数据大小倾斜——部分记录的大小远远大于平均值。
2如何收集倾斜数据
在reduce方法中加入记录map输出键的详细情况的功能。
public static final String MAX_VALUES = "skew.maxvalues";
private int maxValueThreshold;
@Override
public void configure(JobConf job) {
maxValueThreshold = job.getInt(MAX_VALUES, 100);
}
@Override
public void reduce(Text key, Iterator<Text> values,
OutputCollector<Text, Text> output,
Reporter reporter) throws IOException {
int i = 0;
while (values.hasNext()) {
values.next();
i++;
}
if (++i > maxValueThreshold) {
log.info("Received " + i + " values for key " + key);
}
}
3减少数据倾斜的方法
方法1抽样和范围分区
可以通过对原始数据进行抽样得到的结果集来预设分区边界值。
方法2自定义分区
另一个抽样和范围分区的替代方案是基于输出键的背景知识进行自定义分区。例如如果map输出键的单词来源于一本书。其中大部分必然是省略词stopword。那么就可以将自定义分区将这部分省略词发送给固定的一部分reduce实例。而将其他的都发送给剩余的reduce实例。
方法3Combine
使用Combine可以大量地减小数据频率倾斜和数据大小倾斜。在可能的情况下combine的目的就是聚合并精简数据。
20.6 常用的调优参数
1资源相关参数
a以下参数是在用户自己的mr应用程序中配置就可以生效mapred-default.xml
配置参数 | 参数说明 |
---|---|
mapreduce.map.memory.mb | 一个Map Task可使用的资源上限单位:MB默认为1024。如果Map Task实际使用的资源量超过该值则会被强制杀死。 |
mapreduce.reduce.memory.mb | 一个Reduce Task可使用的资源上限单位:MB默认为1024。如果Reduce Task实际使用的资源量超过该值则会被强制杀死。 |
mapreduce.map.cpu.vcores | 每个Map task可使用的最多cpu core数目默认值: 1 |
mapreduce.reduce.cpu.vcores | 每个Reduce task可使用的最多cpu core数目默认值: 1 |
mapreduce.reduce.shuffle.parallelcopies | 每个reduce去map中拿数据的并行数。默认值是5 |
mapreduce.reduce.shuffle.merge.percent | buffer中的数据达到多少比例开始写入磁盘。默认值0.66 |
mapreduce.reduce.shuffle.input.buffer.percent | buffer大小占reduce可用内存的比例。默认值0.7 |
mapreduce.reduce.input.buffer.percent | 指定多少比例的内存用来存放buffer中的数据默认值是0.0 |
b应该在yarn启动之前就配置在服务器的配置文件中才能生效yarn-default.xml
配置参数 | 参数说明 |
---|---|
yarn.scheduler.minimum-allocation-mb 1024 | 给应用程序container分配的最小内存 |
yarn.scheduler.maximum-allocation-mb 8192 | 给应用程序container分配的最大内存 |
yarn.scheduler.minimum-allocation-vcores 1 | 每个container申请的最小CPU核数 |
yarn.scheduler.maximum-allocation-vcores 32 | 每个container申请的最大CPU核数 |
yarn.nodemanager.resource.memory-mb 8192 | 给containers分配的最大物理内存 |
cshuffle性能优化的关键参数应在yarn启动之前就配置好mapred-default.xml
配置参数 | 参数说明 |
---|---|
mapreduce.task.io.sort.mb 100 | shuffle的环形缓冲区大小默认100m |
mapreduce.map.sort.spill.percent 0.8 | 环形缓冲区溢出的阈值默认80% |
2容错相关参数(mapreduce性能优化)
配置参数 | 参数说明 |
---|---|
mapreduce.map.maxattempts | 每个Map Task最大重试次数一旦重试参数超过该值则认为Map Task运行失败默认值4。 |
mapreduce.reduce.maxattempts | 每个Reduce Task最大重试次数一旦重试参数超过该值则认为Map Task运行失败默认值4。 |
mapreduce.task.timeout | Task超时时间经常需要设置的一个参数该参数表达的意思为如果一个task在一定时间内没有任何进入即不会读取新的数据也没有输出数据则认为该task处于block状态可能是卡住了也许永远会卡主为了防止因为用户程序永远block住不退出则强制设置了一个该超时时间单位毫秒默认是600000。如果你的程序对每条输入数据的处理时间过长比如会访问数据库通过网络拉取数据等建议将该参数调大该参数过小常出现的错误提示是“AttemptID:attempt_14267829456721_123456_m_000224_0 Timed out after 300 secsContainer killed by the ApplicationMaster.”。 |
21 HDFS小文件优化方法
1HDFS小文件弊端
HDFS上每个文件都要在namenode上建立一个索引这个索引的大小约为150byte这样当小文件比较多的时候就会产生很多的索引文件一方面会大量占用namenode的内存空间另一方面就是索引文件过大是的索引速度变慢。
2解决的方式
1Hadoop本身提供了一些文件压缩
的方案。
2从系统层面改变现有HDFS存在的问题其实主要还是小文件的合并
然后建立比较快速的索引。
3Hadoop自带小文件解决方案
1Hadoop Archive
:
是一个高效地将小文件放入HDFS块中的文件存档工具它能够将多个小文件打包成一个HAR文件以减少namenode的内存使用。
2Sequence file
sequence file由一系列的二进制key/value组成如果为key小文件名value为文件内容则可以将大批小文件合并成一个大文件。
3CombineFileInputFormat
CombineFileInputFormat是一种新的inputformat用于将多个文件合并成一个单独的split另外它会考虑数据的存储位置。
4小文件优化(实战经验)
对于大量小文件Job可以开启JVM重用会减少45%运行时间。
JVM重用
理解一个map运行一个jvm重用的话在一个map在jvm上运行完毕后jvm继续运行其他jvm
具体设置mapreduce.job.jvm.numtasks值在10-20之间。