mapreduce中控制mapper的数量
很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数决定。在默认情况下,最终input占据了多少block,就应该启动多少个Mapper。如果输入的文件数量巨大,但是每个文件的size都小于HDFS的blockSize,那么会造成启动的Mapper等于文件的数量(即每个文件都占据了一个block),那么很可能造成启动的Mapper数量超出限制而导致崩溃。这些逻辑确实是正确的,但都是在默认情况下的逻辑。其实如果进行一些客户化的设置,就可以控制了。
在Hadoop中,设置Map task的数量不像设置Reduce task数量那样直接,即:不能够通过API直接精确的告诉Hadoop应该启动多少个Map task。
你也许奇怪了,在API中不是提供了接口org.apache.hadoop.mapred.JobConf.setNumMapTasks(int n)吗?这个值难道不可以设置Map task的数量吗?这个API的确没错,在文档上解释”Note: This is only a hint to the framework.“,即这个值对Hadoop的框架来说仅仅是个提示,不起决定性的作用。也就是说,即便你设置了,也不一定得到你想要的效果。
1. InputFormat介绍
在具体设置Map task数量之前,非常有必要了解一下与Map-Reduce输入相关的基础知识。
这个接口(org.apache.hadoop.mapred.InputFormat)描述了Map-Reduce job的输入规格说明(input-specification),它将所有的输入文件分割成逻辑上的InputSplit,每一个InputSplit将会分给一个单独的mapper;它还提供RecordReader的具体实现,这个Reader从逻辑的InputSplit上获取input records并传给Mapper处理。
InputFormat有多种具体实现,诸如FileInputFormat(处理基于文件的输入的基础抽象类), DBInputFormat(处理基于数据库的输入,数据来自于一个能用SQL查询的表),KeyValueTextInputFormat(特殊的FineInputFormat,处理Plain Text File,文件由回车或者回车换行符分割成行,每一行由key.value.separator.in.input.line分割成Key和Value),CompositeInputFormat,DelegatingInputFormat等。在绝大多数应用场景中都会使用FileInputFormat及其子类型。
通过以上的简单介绍,我们知道InputFormat决定着InputSplit,每个InputSplit会分配给一个单独的Mapper,因此InputFormat决定了具体的Map task数量。
2. FileInputFormat中影响Map数量的因素
在日常使用中,FileInputFormat是最常用的InputFormat,它有很多具体的实现。以下分析的影响Map数量的因素仅对FileInputFormat及其子类有效,其他非FileInputFormat可以去查看相应的 getSplits(JobConf job, int numSplits) 具体实现即可。
请看如下代码段(摘抄自org.apache.hadoop.mapred.FileInputFormat.getSplits,hadoop-0.20.205.0源代码):
- long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits);
- long minSize = Math.max(job.getLong("mapred.min.split.size", 1), minSplitSize);
- for (FileStatus file: files) {
- Path path = file.getPath();
- FileSystem fs = path.getFileSystem(job);
- 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) {
- String[] splitHosts = getSplitHosts(blkLocations,length-bytesRemaining, splitSize, clusterMap);
- splits.add(new FileSplit(path, length-bytesRemaining, splitSize, splitHosts));
- bytesRemaining -= splitSize;
- }
- if (bytesRemaining != 0) {
- splits.add(new FileSplit(path, length-bytesRemaining, bytesRemaining, blkLocations[blkLocations.length-1].getHosts()));
- }
- } else if (length != 0) {
- String[] splitHosts = getSplitHosts(blkLocations,0,length,clusterMap);
- splits.add(new FileSplit(path, 0, length, splitHosts));
- } else {
- //Create empty hosts array for zero length files
- splits.add(new FileSplit(path, 0, length, new String[0]));
- }
- }
- return splits.toArray(new FileSplit[splits.size()]);
- protected long computeSplitSize(long goalSize, long minSize, long blockSize) {
- return Math.max(minSize, Math.min(goalSize, blockSize));
- }
totalSize:是整个Map-Reduce job所有输入的总大小。
numSplits:来自job.getNumMapTasks(),即在job启动时用org.apache.hadoop.mapred.JobConf.setNumMapTasks(int n)设置的值,给M-R框架的Map数量的提示。
goalSize:是输入总大小与提示Map task数量的比值,即期望每个Mapper处理多少的数据,仅仅是期望,具体处理的数据数由下面的computeSplitSize决定。
minSplitSize:默认为1,可由子类复写函数protected void setMinSplitSize(long minSplitSize) 重新设置。一般情况下,都为1,特殊情况除外。
minSize:取的1和mapred.min.split.size中较大的一个。
blockSize:HDFS的块大小,默认为64M,一般大的HDFS都设置成128M。
splitSize:就是最终每个Split的大小,那么Map的数量基本上就是totalSize/splitSize。
接下来看看computeSplitSize的逻辑:首先在goalSize(期望每个Mapper处理的数据量)和HDFS的block size中取较小的,然后与mapred.min.split.size相比取较大的。
3. 如何调整Map的数量
有了2的分析,下面调整Map的数量就很容易了。
3.1 减小Map-Reduce job 启动时创建的Mapper数量
当处理大批量的大数据时,一种常见的情况是job启动的mapper数量太多而超出了系统限制,导致Hadoop抛出异常终止执行。解决这种异常的思路是减少mapper的数量。具体如下:
3.1.1 输入文件size巨大,但不是小文件
这种情况可以通过增大每个mapper的input size,即增大minSize或者增大blockSize来减少所需的mapper的数量。增大blockSize通常不可行,因为当HDFS被hadoop namenode -format之后,blockSize就已经确定了(由格式化时dfs.block.size决定),如果要更改blockSize,需要重新格式化HDFS,这样当然会丢失已有的数据。所以通常情况下只能通过增大minSize,即增大mapred.min.split.size的值。
3.1.2 输入文件数量巨大,且都是小文件
所谓小文件,就是单个文件的size小于blockSize。这种情况通过增大mapred.min.split.size不可行,需要使用FileInputFormat衍生的CombineFileInputFormat将多个input path合并成一个InputSplit送给mapper处理,从而减少mapper的数量。具体细节稍后会更新并展开。
3.2 增加Map-Reduce job 启动时创建的Mapper数量
增加mapper的数量,可以通过减小每个mapper的输入做到,即减小blockSize或者减小mapred.min.split.size的值。
参考资料
http://yaseminavcular.blogspot.com/2011/06/how-to-set-number-of-maps-with-hadoop.html
http://svn.apache.org/repos/asf/hadoop/common/tags/release-0.20.205.0
mapreduce中控制mapper的数量的更多相关文章
- 深度分析如何在Hadoop中控制Map的数量
深度分析如何在Hadoop中控制Map的数量 guibin.beijing@gmail.com 很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数 ...
- 深度分析如何在Hadoop中控制Map的数量(摘抄)
很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数决定.在默认情况下,最终input占据了多少block,就应该启动多少个Mapper.如果输入的 ...
- 【Hadoop】三句话告诉你 mapreduce 中MAP进程的数量怎么控制?
1.果断先上结论 1.如果想增加map个数,则设置mapred.map.tasks 为一个较大的值. 2.如果想减小map个数,则设置mapred.min.split.size 为一个较大的值. 3. ...
- [Hadoop源码解读](二)MapReduce篇之Mapper类
前面在讲InputFormat的时候,讲到了Mapper类是如何利用RecordReader来读取InputSplit中的K-V对的. 这一篇里,开始对Mapper.class的子类进行解读. 先回忆 ...
- Hadoop学习之路(二十三)MapReduce中的shuffle详解
概述 1.MapReduce 中,mapper 阶段处理的数据如何传递给 reducer 阶段,是 MapReduce 框架中 最关键的一个流程,这个流程就叫 Shuffle 2.Shuffle: 数 ...
- go中控制goroutine数量
控制goroutine数量 前言 控制goroutine的数量 通过channel+sync 使用semaphore 线程池 几个开源的线程池的设计 fasthttp中的协程池实现 Start Sto ...
- MapReduce中的partitioner
1.日志源文件: 1363157985066 13726230503 00-FD-07-A4-72-B8:CMCC 120.196.100.82 i02.c.aliimg.com 24 27 2481 ...
- Hadoop案例(七)MapReduce中多表合并
MapReduce中多表合并案例 一.案例需求 订单数据表t_order: id pid amount 1001 01 1 1002 02 2 1003 03 3 订单数据order.txt 商品信息 ...
- hadoop学习第四天-Writable和WritableComparable序列化接口的使用&&MapReduce中传递javaBean的简单例子
一. 为什么javaBean要继承Writable和WritableComparable接口? 1. 如果一个javaBean想要作为MapReduce的key或者value,就一定要实现序列化,因为 ...
随机推荐
- Expo大作战(七)--expo如何使用Genymotion模拟器
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,将全部来与官网 我猜去全部机翻+个人 ...
- [Android] 图片裁剪总结——调用系统裁剪
花了两天时间看了下android的图片裁剪功能的实现.其实刚开始做这个我挺虚的,以为整个功能都需要自己写出来,但查了些资料,发现android已经提供了裁剪功能,需要的话自己调用就成了.soga,这下 ...
- Kafka 处理器客户端介绍
[编者按]本文作者为 Bill Bejeck,主要介绍如何有效利用新的 Apache Kafka 客户端来满足数据处理需求.文章系国内 ITOM 管理平台 OneAPM 编译呈现,以下为正文. 如果你 ...
- SQL2005的SSMS连接SQL2012会有问题
SQL2005的SSMS连接SQL2012会有问题 如果用SQL2005的SSMS连接SQL2012会产生“索引数组越界”的问题并且使用不了 反过来使用SQL2012的SSMS连接SQL2005就没有 ...
- mysql中删除同一行会经常出现死锁?太可怕了
之前有一个同事问到我,为什么多个线程同时去做删除同一行数据的操作,老是报死锁,在线上已经出现好多次了,我问了他几个问题: 1. 是不是在一个事务中做了好几件事情? 答:不是,只做一个删除 ...
- 破解 jar 包之直接修改 .class 文件方式
一.常规 JAVA 软件破解流程 先讲一下常规jar包的破解流程. 1. 快速定位. 1) 通过procmon监控相关软件,查看程序都访问了些啥. 2) 用jd-gu ...
- Windows7系统中怎么Ping端口?利用telnet命令Ping 端口的方法
telnet www.baidu.com 80 端口打开的情况下,链接成功,则进入Telnet页面(全黑的),证明端口可用.
- 《MySQL技术内幕:InnoDB存储引擎(第2版)》书摘
MySQL技术内幕:InnoDB存储引擎(第2版) 姜承尧 第1章 MySQL体系结构和存储引擎 >> 在上述例子中使用了mysqld_safe命令来启动数据库,当然启动MySQL实例的方 ...
- MySQL 8.0新特性之原子DDL
文章来源:爱可生云数据库 简介 MySQL8.0 开始支持原⼦ DDL(atomic DDL),数据字典的更新,存储引擎操作,写⼆进制日志结合成了一个事务.在没有原⼦DDL之前,DROP TABLE ...
- Java MySQL数据类型对照
Java MySQL数据类型对照 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述 varchar L+N VARCHAR java.lang.S ...