在Hadoop安装目录中你会找到包含Hadoop样例程序的JAR文件,你可以用它来试用Hadoop。在你执行这些样例程序以前,你应该保证你的安装是完全的和你的执行时环境的设置是正确的。我们在前面小节中提到,check_basic_env.sh脚本能够帮助你校验安装,如果安装有任何错误,它会提示你改正。
hadoop-0.19.0-examples.jar文件包含着数个可以直接运行的样例程序。我们在图标1-4中列出包含在这个JAR文件的样例程序。
图表 1‑4 hadoop-0.19.0-examples.jar文件中的样例程序
程序 |
描述 |
aggregatewordcount |
计算输入文件中文字个数的基于聚合的MapReduce程序。 |
aggregatewordhist |
生成输入文件中文字个数的统计图的基于聚合的MapReduce程序。 |
grep |
计算输入文件中匹配正则表达式的文字个数的MapReduce程序。 |
join |
合并排序的平均分割的数据集的作业。 |
multifilewc |
计算几个文件的文字个数的作业。 |
pentomino |
解决五格拼版问题的分块分层的MapReduce程序。 |
pi |
使用蒙地卡罗法计算PI的MapReduce程序。 |
randomtextwriter |
在一个节点上写10G随机文本的MapReduce程序。 |
randomwriter |
在每个节点上写10G随机数据的MapReduce程序。 |
sleep |
在每个Map和Reduce作业中休憩的程序。 |
sort |
排序随机写入器生成的数据的MapReduce程序。 |
sudoku |
一个九宫格游戏的解决方案。 |
wordcount |
在输入文件中统计文字个数的统计器。 |
PI计算器样例程序通过蒙地卡罗法计算PI值。网址http://www.chem.unl.edu/zeng/joy/mclab/mcintro.html提供了关于这个算法的技术讨论。抽样数量是正方形内随机集合的点数。抽样数越多,PI值的计算就越精确。为了程序的简单性,我们只用很少的操作粗略的计算出PI的值。
PI程序使用了两个整形参数。Map作业数量和每个Map作业中的抽样数量。计算中的总共的抽样数量是Map作业的数量乘以每个Map作业中的抽样数量。
Map作业在1乘1的矩形面积内产生随机的点。对于其中的每个抽样如果满足X2+Y2 <=1, 那么这个点就在圆的里面。否则,这个点就在圆的外面。Map作业输出键值为1或者0,1代表在直径为1的圆内,0代表在直径为1的圆外,映射的数据值均为1,Reduce任务计算圆内点的数量和圆外点的数量。这两个数量的比例就是极限值PI.
在这个样例程序中,为了使程序执行得更快和有更少的输出,你会选择2个Map作业,每个作业有10个抽样,一共有20个抽样。
如果你想执行这个程序,你需要改变你的工作目录去HADOOP_HOME(通过 cd ${HADOOP_HOME}),然后,键入命令如下:
jason@cloud9:~/src/hadoop-0.19.0$ hadoop jar hadoop-0.19.0-examples.jar pi 2 10
bin/hadoop jar命令提交作业到集群中。它通过三个步骤处理命令行参数,每一个步骤处理命令行参数中的一部分。我们会在第5章会看到处理参数的细节。但是现在,我们只需要知道hadoop_0.19.0-examples.jar文件包含此应用程序的主类,而且这个类接受3个参数。
列表1-3就是此应用程序的输出。
列表 1-3 样例PI程序的输出
Number of Maps = 2 Samples per Map = 10
Wrote input for Map #0
Wrote input for Map #1
Starting Job
jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
mapred.FileInputFormat: Total input paths to process : 2
mapred.FileInputFormat: Total input paths to process : 2
mapred.JobClient: Running job: job_local_0001
mapred.FileInputFormat: Total input paths to process : 2
mapred.FileInputFormat: Total input paths to process : 2
mapred.MapTask: numReduceTasks: 1
mapred.MapTask: io.sort.mb = 100
mapred.MapTask: data buffer = 79691776/99614720
mapred.MapTask: record buffer = 262144/327680
mapred.JobClient: map 0% reduce 0%
mapred.MapTask: Starting flush of map output
mapred.MapTask: bufstart = 0; bufend = 32; bufvoid = 99614720
mapred.MapTask: kvstart = 0; kvend = 2; length = 327680
mapred.LocalJobRunner: Generated 1 samples
mapred.MapTask: Index: (0, 38, 38)
mapred.MapTask: Finished spill 0
mapred.LocalJobRunner: Generated 1 samples.
mapred.TaskRunner: Task 'attempt_local_0001_m_000000_0' done.
mapred.TaskRunner: Saved output of task 'attempt_local_0001_m_000000_0' ➥
to file:/home/jason/src/hadoop-0.19.0/test-mini-mr/outmapred.
MapTask: numReduceTasks: 1
mapred.MapTask: io.sort.mb = 100
mapred.JobClient: map 0% reduce 0%
mapred.LocalJobRunner: Generated 1 samples
mapred.MapTask: data buffer = 79691776/99614720
mapred.MapTask: record buffer = 262144/327680
mapred.MapTask: Starting flush of map output
mapred.MapTask: bufstart = 0; bufend = 32; bufvoid = 99614720
mapred.MapTask: kvstart = 0; kvend = 2; length = 327680
mapred.JobClient: map 100% reduce 0%
mapred.MapTask: Index: (0, 38, 38)
mapred.MapTask: Finished spill 0
mapred.LocalJobRunner: Generated 1 samples.
mapred.TaskRunner: Task 'attempt_local_0001_m_000001_0' done.
mapred.TaskRunner: Saved output of task 'attempt_local_0001_m_000001_0' ➥
to file:/home/jason/src/hadoop-0.19.0/test-mini-mr/out
mapred.ReduceTask: Initiating final on-disk merge with 2 files
mapred.Merger: Merging 2 sorted segments
mapred.Merger: Down to the last merge-pass, with 2 segments left of ➥
total size: 76 bytes
mapred.LocalJobRunner: reduce > reduce
mapred.TaskRunner: Task 'attempt_local_0001_r_000000_0' done.
mapred.TaskRunner: Saved output of task 'attempt_local_0001_r_000000_0' ➥
to file:/home/jason/src/hadoop-0.19.0/test-mini-mr/out
mapred.JobClient: Job complete: job_local_0001
mapred.JobClient: Counters: 11
mapred.JobClient: File Systems
mapred.JobClient: Local bytes read=314895
mapred.JobClient: Local bytes written=359635
mapred.JobClient: Map-Reduce Framework
mapred.JobClient: Reduce input groups=2
mapred.JobClient: Combine output records=0
mapred.JobClient: Map input records=2
mapred.JobClient: Reduce output records=0
mapred.JobClient: Map output bytes=64
mapred.JobClient: Map input bytes=48
mapred.JobClient: Combine input records=0
mapred.JobClient: Map output records=4
mapred.JobClient: Reduce input records=4
Job Finished in 2.322 seconds
Estimated value of PI is 3.8
请注意Hadoop项目使用阿帕奇基金的log4j包来处理日志。缺省情况下,框架的输出日志是以时间戳开始的,后面跟着日志级别和产生消息的类名。除此之外,缺省情况下只有INFO和更高级别日志消息才会被打印出来。为了简介,我已经从输出中移除了时间戳和日志级别。
在日志中,你最感兴趣的就是日志输出的最后一行,它说” 计算的PI值是…”。这意味着你的Hadoop安装是成功的,它能够正确的执行你的应用程序。
下面我们将一步一步的详细查看列表2-3的输出,这能帮助你理解这个样例程序是怎么工作的,甚至可以找到程序是否出现错误。
第一段日志是在Hadoop初始化PI计算器程序时输出的,我们可以看到,你的输入是2个Map作业和每个Map作业有10个抽样。
Number of Maps = 2 Samples per Map = 10
Wrote input for Map #0
Wrote input for Map #1
然后,框架程序启动并且接管控制流,它进行输入分割(把输入分成不相干的部分称为输入分割)。
你可以从下面一行中获得作业ID,你能使用作业ID在作业控制工具中找到此作业。
Running job: job_local_0001
通过下面一行我们可以得知,一共有两个输入文件和两个输入分割。
jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
mapred.FileInputFormat: Total input paths to process : 2
mapred.FileInputFormat: Total input paths to process : 2
mapred.JobClient: Running job: job_local_0001
mapred.FileInputFormat: Total input paths to process : 2
mapred.FileInputFormat: Total input paths to process : 2
映射作业的输出会被划分为不同的输出块,每一个输出块都是排序的,这个过程被称为混淆过程。包含每一个排序的输出块的文件成为输出块。对于每一个Reduce作业,框架会从Map作业的输出中得到输出块,然后合并并且排序这些输出块得到排序块,这个过程成为排序过程。
在列表2-3的下一部分,我们可以看到Map作业的混淆过程执行的详细信息。框架获得所有Map作业的输出记录,然后把这些输出输入给唯一的一个Reduce作业(numReduceTasks:1)。如果你指定了多个Reduce作业,对于每一个Reduce作业你就会看到一个类似Finished spill N的日志。剩下的日志是用来记录输出缓冲,我们并不关注这些。
下面,你会看到:
mapred.MapTask: numReduceTasks: 1
...
mapred.MapTask: Finished spill 0
mapred.LocalJobRunner: Generated 1 samples.
mapred.TaskRunner: Task 'attempt_local_0001_m_000000_0' ➥
done.mapred.TaskRunner: Saved output of task ➥
'attempt_local_0001_m_000000_0' ➥
to file:/home/jason/src/hadoop-0.19.0/test-mini-mr/out
Generated 1 samples是Map作业的最终状态的输出。Hadoop框架告诉你,第一个Map作业通过作业’attempt_local_0001_m_000000_0”完成的,而且输出已经保存到缺省的文件系统file:/home/Jason/src/hadoop-0.19.0/test-mini-mr/out。
下面一部分是排序过程的输出:
mapred.ReduceTask: Initiating final on-disk merge with 2 files
mapred.Merger: Merging 2 sorted segments
mapred.Merger: Down to the last merge-pass, with 2 segments left of ➥
total size: 76 bytes
根据命令行参数,列表2-3运行的程序中有2个Map作业和一个Reduce作业。因为仅仅存在一个Reduce作业,所有的Map作业的输出会被组织成为一个排序的排序块。但是,两个Map作业会产生两个输出块进入排序阶段。每一个Reduce作业会在输出目录下产生一个名字为part-ON的输出文件,N是Reduce作业以0开始的递增的序数。通常来说,名字的数字部分是5位数字构成的,如果不够5位数以0补齐。
日志输出的下一部分说明了唯一的Reduce任务的执行情况:
mapred.LocalJobRunner: reduce > reduce
mapred.TaskRunner: Task 'attempt_local_0001_r_000000_0' done.
mapred.TaskRunner: Saved output of task 'attempt_local_0001_r_000000_0' to ➥
file:/home/jason/src/hadoop-0.19.0/test-mini-mr/out
我们可以看出,样例程序把Reduce作业的输出写入文件attempt_local_0001_4_000000_0,然后,把它重命名为part-00000,保存在作业的输出目录中。
下面的日志的输出提供了详细的作业完成信息。
mapred.JobClient: Job complete: job_local_0001
mapred.JobClient: Counters: 11
mapred.JobClient: File Systems
mapred.JobClient: Local bytes read=314895
mapred.JobClient: Local bytes written=359635
mapred.JobClient: Map-Reduce Framework
mapred.JobClient: Reduce input groups=2
mapred.JobClient: Combine output records=0
mapred.JobClient: Map input records=2
mapred.JobClient: Reduce output records=0
mapred.JobClient: Map output bytes=64
mapred.JobClient: Map input bytes=48
mapred.JobClient: Combine input records=0
mapred.JobClient: Map output records=4
mapred.JobClient: Reduce input records=4
最后的两行日志并不是框架打印的,而是由PiEstimator程序代码打印的。
Job Finished in 2.322 seconds
Estimated value of PI is 3.8
Hadoop框架提供了用来测试分布式文件系统和运行在分布式文件系统的MapReduce作业的样例程序,这些测试程序被包含在hadoop-0.19.0-test.jar文件中。图标1-5是这些测试程序的列表和他们提供的功能:
图表 1‑5 hadoop-0.19.0-tests.jar文件中的测试程序
测试 |
描述 |
DFSCIOTest |
测试libhdfs中的分布式I/O的基准。Libhdfs是一个为C/C++应用程序提供HDFS文件服务的共享库。 |
DistributedFSCheck |
文件系统一致性的分布式检查。 |
TestDFSIO |
分布式的I/O基准。 |
clustertestdfs |
对分布式文件系统的伪分布式测试。 |
dfsthroughput |
测量HDFS的吞吐量。 |
filebench |
SequenceFileInputFormat和SequenceFileOutputFormat的基准,这包含BLOCK压缩,RECORD压缩和非压缩的情况。TextInputFormat和TextOutputFormat的基准,包括压缩和非压缩的情况。 |
loadgen |
通用的MapReduce加载产生器。 |
mapredtest |
MapReduce作业的测试和检测。 |
mrbench |
创建大量小作业的MapReduce基准。 |
nnbench |
NameNode的性能基准。 |
testarrayfile |
对有键值对的文本文件的测试。 |
testbigmapoutput |
这是一个MapReduce作业,它用来处理不可分割的大文件来产生一个标志MapReduce作业。 |
testfilesystem |
文件系统读写测试。 |
testipc |
Hadoop核心的进程间交互测试。 |
testmapredsort |
用于校验MapReduce框架的排序的程序。 |
testrpc |
对远程过程调用的测试。 |
testsequencefile |
对包含二进制键值对的文本文件的测试。 |
testsequencefileinputformat |
对序列文件输入格式的测试。 |
testsetfile |
对包含二进制键值对文本文件的测试。 |
testtextinputformat |
对文本输入格式的测试。 |
threadedmapbench |
对比输出一个排序块的Map作业和输出多个排序块的Map作业的性能。 |