1.1 Hadoop简介
Hadoop MapReduce是一个勇于处理海量数据的分布式计算框架。这个框架解决了诸如数据分布式存储、作业调度、容错、机器间通信等复杂问题,可以使用没有并行处理或者分布式计算经验的工程师,也能轻松些出结构简单、应用于成百上千台及其处理大规模数据的并行分布式程序
Hadoop MapReduce基于“分而治之的思想,将任务抽象成map和reduce两个计算过程,可以简单理解为“分散运算-归并结果”的过程。一个MapReduce程序首先会吧输入数据分割成不相关的果敢键/值对(key1/value1)集合,这些键/值对会由多个map任务来并行地处理。MapReduce会对map的输出(一些中间键/值对key2/value2集合)按照key2进行排序,排序使用memcmp的方式对key在内存中字节数组比较后进行升序排序,并将属于同一个key2的所有value2组合在一起作为reduce任务的输入,由reduce任务计算出最终结果并输出key3/value3。作为一个优化,同一个计算节点上的key2/value2会通过conbine在本地归并。基本流程如下:
(input)<k1,v1> =>
map => <k2,v2> => combine => <k2,v2’> =>
reduce => <k3,v3>(output)
通常计算任务的输入和输出都是存放在文件里,并且这些文件被存放在Hadoop分布式文件系统HDFS(Hadoop Distributed File System)中,系统会尽量调度计算任务到数据所在的节点上运行,而不是尽量将数据移动到计算节点桑,减少大量数据在网络上传输,尽量节省带宽消耗
应用程序开发人员一般情况下需要关心途中灰色的部分,单机程序需要处理数据读取和写入、数据处理;Hadoop程序需要实现map和reduce,而数据读取和写入、map和reduce之间的数据传输、容错处理等由Hadoop MapReduce和HDFS自动完成。
1.2 Streaming 简介
Hadoop MapReduce 和HDFS采用java实现,默认提供java编程接口,另外提供了c++编程接口和Streaming矿建,Streaming框架语序任何程序语言实现的程序在Hadoop MapReduce中使用,方便已有程序向Hadoop平台移植。
Streaming 的原理是用Java实现一个包装用户程序的MapReduce程序,该程序负责调用MapReduce Java接口获取key/value对输入,创建一个新的进程启动包装的用户程序,将数据通过管道传递给包装的用户程序处理,然后调用MapReduce Java接口将用户程序的输出切分成key/value对输出。如下图所示,其中Streaming Java Mapper通过管道将key/value输入传递给用户mapper程序的标准输入,并获取用户mapper程序的标准输入;Streaming Java Reducer 调用 java接口通过InputFormat从HDFS获取输入数据,从管道将key/value传递给用户reducer程序的标准输入,获取用户reducer程序的标准输出并调用Java接口通过OutputFormat输出数据;用户mapper和reducer程序负责处理数据,都从标准输入读取数据,向标准输出写入数据。
1.3 Hadoop Streaming QuickStart
下面介绍一个简单实用的Hadoop Streaming实例:分布式grep,它将文本中包含某些关键字的行过滤出来。mapper程序使用grep。reduce使用cat将输入直接输出,具体如下:
$HADOOP_HOME/bin/hadoopstreaming \
-input /user/test/input -output /user/test/output \
-mapper “mapper.sh” -reducer “cat” \
-file mapper.sh \
-jobconf mapred.job.name=”dist-grep”
其中-mapper “mapper.sh”制定mapper程序为mapper.sh(如果mapper或reducer程序是由多条命令组成的,请用一个脚本把他们包装起来,而不是-mapper"cmd1;cmd2;cmd3"这样的形式),mapper.sh是通过-file分发到节点的,它的输入是来自标准输入的文本行,输出是包含关键字的文本行,mapper.sh内容如下:
#/bin/sh
grep -E "keyword1|keyword2|keyword3"
exit()
-reduce"cat" 指定reduce陈虚伪unix cat 它的输入是grep的输出,它的输出与输入相同;最后保存到HDFS的输出结果就是包含关键字的所有输入行。
利用MapReduce和Streaming矿建,可以很容易实现一些常见的分布式ic狐狸,如下面示例实现了分布式排序。
$HADOOP_HOME/bin/hadoopstreaming \
-input /user/test/input -output /user/test/output \
-mapper “cat” \
-reducer “cat” \
-jobconf mapred.reduce.tasks=1\
-jobconf mapred.job.name=”dist-sort”
其中mapper和reducer都是直接将标准输入原样输出,由于设置了reduce任务数为1,搜友mapper的输出都会分配到这个reduce处理,MapReduce框架会将reducer的输入按key自动排序,所以reduce输入就是按key升序排好序的,但是reduce只有一个性能不是很好。
在实际的开发过程中,开发人员需要考虑下面几个方面的问题,其中1,2是必须实现的:
1)Mapper 程序:对输入key/value数据进行处理:
2)Reduce程序: 对mapper的输出进行归并处理;
3)Combine: 在本地对一个计算节点上的mapper输出进行归并;
4)Partitioner: 将mapper的输出分配到reducer;
5)InputFormat/OutputFormat: 对输入数据进行切分,保存输出数据。
2 Streaming优缺点分析
2.1 Streaming的优点
1)使用Streaming进行MapReduce程序开发效率较高
一方面用其他语言(包括脚本语言)编写的程序可以方便地一直到Hadoop平台上,程序只需要按照一定的格式从标准输入独缺数据、向标准输出写数据就可以在Hadoop平台上使用,原有的单机程序稍加改动就可以在Hadoop平台进行分布式处理;另一方面勇于Streaming的程序可以在单机上用下面的方式运行,因此可以先用小规模数据在单机调试使用本地的调试方法和调试用具,节省开发测试的时间。
cat input | mapper | sort | reduce > output
2)使用Streaming的MapReduce运行效率较高
对于CPU密集的计算,有些语言如C/C++编写的程序可能比用Java编写的程序效率更高一些,如果原有程序做过成熟的优化那么性能可能更好。
3)使用Streaming便于平台进行资源控制
由于不同的应用对资源的 需求不同,使用统一的JVM参数控制资源不能满足要求,在Streamin框架中通过limit等方式可以灵活地限制应用程序使用内存等资源
2.2 Streamig的局限
1)Hadoop Streamin默认只能处理文本数据,如果要对二进制数据进行处理,比较好的方法是将二进制的key和value进行base64的编码转成文本,在本地程序中在进行base64的解码
2)Streaming中的mapper和reducer默认只能向标准输出写数据,不能方便的处理多路输出。多路输出处理方式参考以下第四个大标题。
3)用Java编写的MapReduce程序直接处理框架从输入数据中得到的key/value对,在Streamin中Java程序不再处理key/value对,而是通过管道写到mapper程序的标准输入,mapper程序再从key/value中解析出key/value对,这个过程多了两次数据拷贝和解析(分割),带来一定的开销。对于reduce也是一样的。
3 Streaming命令说明
3.1Streaming 命令
$HADOOP_HOME/bin/hadoop streaming args
其中args是streaming参数,下面是参数列表:
-input <path> 输入数据路径
-output <path> 输出数据路径
-mapper <cmd|JavaClassName> mapper可执行程序或Java类
-reducer <cmd|JavaClassName> reduce可执行程序或Java类
-file <file> Optional 分发本地文件
-cacheFile <file> Optional 分发HDFS文件
-cacheArchive <file> Optional 分发HDFS压缩文件
-numReduceTasks <num> Optional reduce任务个数
-jobconf | -D NAME=VALUE Optional 作业配置参数
-combiner <JavaClassName> Optional Combiner Java类
-partitioner <JavaClassName> Optional Partitioner Java类
-inputformat <JavaClassName> Optional InputFormat Java类
-outputformat <javaClassName> Optional OutputFormat Java类
-inputtreader <spec> Optional InputReader配置
-cmdenv <n>=<v> Optional 传给mapper和reducer的环境变量
-mapdebug <path> Optional mapper失败时运行的debug程序
-reducedebug <path> Optional reducer 失败时运行的debug程序
-verbose Optional 详细输出模式