Hadoop上运行WordCount以及本地调试
本文是在hadoop上运行你的第一个程序,以及如何进行本地调试。如果还没有部署好hadoop环境,请参考之前的文章hadoop在集群上的安装部署
Hadoop Map/Reduce框架的简要介绍
Hadoop Map/Reduce是一个使用简易的软件框架,基于它写出来的应用程序能够运行在由上千个商用机器组成的大型集群上,并以一种可靠容错的方式并行处理上T级别的数据集。
一个Map/Reduce 作业(job) 通常会把输入的数据集切分为若干独立的数据块,由 map任务(task)以完全并行的方式处理它们。框架会对map的输出先进行排序, 然后把结果输入给reduce任务。通常作业的输入和输出都会被存储在文件系统中。 整个框架负责任务的调度和监控,以及重新执行已经失败的任务。
通常,Map/Reduce框架和分布式文件系统是运行在一组相同的节点上的,也就是说,计算节点和存储节点通常在一起。这种配置允许框架在那些已经存好数据的节点上高效地调度任务,这可以使整个集群的网络带宽被非常高效地利用。
Map/Reduce框架由一个单独的master JobTracker 和每个集群节点一个slave TaskTracker共同组成。master负责调度构成一个作业的所有任务,这些任务分布在不同的slave上,master监控它们的执行,重新执行已经失败的任务。而slave仅负责执行由master指派的任务。
应用程序至少应该指明输入/输出的位置(路径),并通过实现合适的接口或抽象类提供map和reduce函数。再加上其他作业的参数,就构成了作业配置(job configuration)。然后,Hadoop的 job client提交作业(jar包/可执行程序等)和配置信息给JobTracker,后者负责分发这些软件和配置信息给slave、调度任务并监控它们的执行,同时提供状态和诊断信息给job-client。
输入与输出
Map/Reduce框架运转在<key, value=””> 键值对上,也就是说, 框架把作业的输入看为是一组<key, value=””> 键值对,同样也产出一组 <key, value=””>键值对做为作业的输出,这两组键值对的类型可能不同。
框架需要对key和value的类(classes)进行序列化操作, 因此,这些类需要实现 Writable接口。 另外,为了方便框架执行排序操作,key类必须实现 WritableComparable接口。
一个Map/Reduce 作业的输入和输出类型如下所示:
(input) <k1, v1=””>-> map -> <k2, v2=””>-> combine -> <k2, v2=””>-> reduce -> <k3, v3=””>(output)
运行wordcount程序
wordcount程序在hadoop的分发包中已经有了,在{HADOOP_HOME}srcexamples中
- [hadoop@hadoop hadoop]$cd /home/hadoop/
- [hadoop@hadoop hadoop]$ mkdir wordcount_classes
- [hadoop@hadoop hadoop]$javac -classpath hadoop-0.17.2.1-core.jar -d wordcount_classes ./com/beoop/WordCount.java
- [hadoop@hadoop hadoop]$jar -cvf /home/hadoop/wordcount.jar -C wordcount_classes/ .
在HDFS上建立wordcount目录
- [hadoop@hadoop hadoop]$ ./bin/hadoop dfs -mkdir wordcount
- [hadoop@hadoop hadoop]$ ./bin/hadoop dfs -mkdir wordcount/input
放入测试文件file01、file02到input目录中,结构如下
- [hadoop@hadoop hadoop]$ ./bin/hadoop dfs -ls wordcount/input/
- /user/hadoop/wordcount/input/file01
- /user/hadoop/wordcount/input/file02
input中的文件内容,file01和file02可以从本地put进去
- [hadoop@hadoop hadoop]$ ./bin/hadoop dfs -cat /user/hadoop/wordcount/input/file01
- Hello World Bye World you are a big star
- [hadoop@hadoop hadoop]$ ./bin/hadoop dfs -cat /user/hadoop/wordcount/input/file02
- Hello Hadoop Goodbye Hadoop
运行wordcount程序,jar文件可以在本地,输入输出应该在HDFS上
- [hadoop@hadoop hadoop]$./bin/hadoop jar /home/hadoop/wordcount.jar com.beoop.WordCount /user/hadoop/wordcount/input /user/hadoop/wordcount/output
- 运行输出信息
- 08/12/11 19:39:39 INFO mapred.FileInputFormat: Total input paths to process : 2
- 08/12/11 19:39:39 INFO mapred.JobClient: Running job: job_200811260234_0027
- 08/12/11 19:39:40 INFO mapred.JobClient: map 0% reduce 0%
- 08/12/11 19:39:47 INFO mapred.JobClient: map 66% reduce 0%
- 08/12/11 19:39:48 INFO mapred.JobClient: map 100% reduce 0%
- 08/12/11 19:39:53 INFO mapred.JobClient: map 100% reduce 11%
- 08/12/11 19:39:55 INFO mapred.JobClient: map 100% reduce 100%
- 08/12/11 19:39:56 INFO mapred.JobClient: Job complete: job_200811260234_0027
- 08/12/11 19:39:56 INFO mapred.JobClient: Counters: 16
- 08/12/11 19:39:56 INFO mapred.JobClient: File Systems
- 08/12/11 19:39:56 INFO mapred.JobClient: Local bytes read=663
- 08/12/11 19:39:56 INFO mapred.JobClient: Local bytes written=1580
- 08/12/11 19:39:56 INFO mapred.JobClient: HDFS bytes read=242
- 08/12/11 19:39:56 INFO mapred.JobClient: HDFS bytes written=228
- 08/12/11 19:39:56 INFO mapred.JobClient: Job Counters
- 08/12/11 19:39:56 INFO mapred.JobClient: Launched map tasks=3
- 08/12/11 19:39:56 INFO mapred.JobClient: Launched reduce tasks=1
- 08/12/11 19:39:56 INFO mapred.JobClient: Data-local map tasks=3
- 08/12/11 19:39:56 INFO mapred.JobClient: Map-Reduce Framework
- 08/12/11 19:39:56 INFO mapred.JobClient: Map input records=4
- 08/12/11 19:39:56 INFO mapred.JobClient: Map output records=38
- 08/12/11 19:39:56 INFO mapred.JobClient: Map input bytes=199
- 08/12/11 19:39:56 INFO mapred.JobClient: Map output bytes=351
- 08/12/11 19:39:56 INFO mapred.JobClient: Combine input records=38
- 08/12/11 19:39:56 INFO mapred.JobClient: Combine output records=31
- 08/12/11 19:39:56 INFO mapred.JobClient: Reduce input groups=30
- 08/12/11 19:39:56 INFO mapred.JobClient: Reduce input records=31
- 08/12/11 19:39:56 INFO mapred.JobClient: Reduce output records=30
本地调试
上面我们已经可以在hadoop上运行程序,但对于日常调试,会比较麻烦,IBM开发了IBM MapReduce Tools 的用语eclipse的插件http://www.alphaworks.ibm.com/tech/mapreducetools,IBM已经将这个插件捐献给了hadoop,0.17以上版本,可以在hadoop目录下的contribeclipse-plugin中可以找到这个插件,和IBM发布的有些改进。hadoop有自己的rpc远程调用框架,所以客户端的hadoop-core.jar必须与服务器一致.不然rpc协议有可能不兼容.
,所以推荐使用hadoop自带的plugin,以防出现鬼魅问题。
安装该插件后,重启eclipse,和平时一样,new->project 选择Map/Reduce project,如下图
输入名字
点击右侧的configure hadoop install directory,选择本地的hadoop的目录
将hadoop的/src/examples中的文件导入到新建的项目中.
在org.apache.hadoop.examples里有我们需要的WordCount.java
在工程的右下脚控制面板上会出现一个大象的图标,点击后会出来配置hadoop服务器的界面
这里的名字随便填个就可以,重要的是host和port,插件默认是localhost:50020,需要改成和之间部署hadoop的时候hadoop-site.xml中的一样。
还需要注意一点的是,Map/Reduce Master 对应mapred.job.tracker,而 DFS Master对应于fs.default.name
我在初次配置的时候写反了,导致出现以下错误
- 2008-12-10 02:38:06,434 INFO org.apache.hadoop.ipc.Server: IPC Server handler 9 on 9001, call getProtocolVersion(org.apache.hadoop.d
- fs.ClientProtocol, 29) from 10.10.1.34:2282: error: java.io.IOException: Unknown protocol to job tracker: org.apache.hadoop.dfs.Clie
- ntProtocol
- java.io.IOException: Unknown protocol to job tracker: org.apache.hadoop.dfs.ClientProtocol
- at org.apache.hadoop.mapred.JobTracker.getProtocolVersion(JobTracker.java:173)
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
- at java.lang.reflect.Method.invoke(Method.java:597)
- at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:446)
- at org.apache.hadoop.ipc.Server$Handler.run(Server.java:896)
根据hadoop在集群上的安装部署中hadoop-site.xml中的配置
- <property>
- <NAME>fs.default.name</NAME>
- <VALUE>hdfs://hadoop:9000/</VALUE>
- </property>
- <property>
- <NAME>mapred.job.tracker</NAME>
- <VALUE>hadoop:9001</VALUE>
- </property>
如上图所示,填上相应的host和port,如果你没在本地设置hosts,那么请用ip代替,或者在C:WINDOWSsystem32driversetchosts文件中加入,在高级设置中可以对hadoop做更为细致的设置。这里略过。
在run dialog中设置输入参数
修改WordCount.java,在run方法中加入下面2句
- conf.set(“hadoop.job.ugi”, “hadoop,hadoop”); //设置hadoop server用户名和密码
- conf.set(“mapred.system.dir”, “/home/hadoop/HadoopInstall/tmp/mapred/system/”); //指定系统路径
在run as菜单中选择run on hadoop选项,运行,弹出选择框,选择刚才配置好的hadoop server,也可以在这里配置新的server。
如果一切正常在console上会有和上面运行结果一样的输出,可以在 http://hadoop:50030/jobtracker.jsp 上监控我们部署的作业的状态。
错误分析
初次运行出现以下错误,主要是因为没有设置用户名和密码而导致的,参照上面调用conf.set手动设置以下就可以了。
- 08/12/11 14:33:04 WARN fs.FileSystem: uri=hdfs://hadoop:9000/
- javax.security.auth.login.LoginException: Login failed: Cannot run program “whoami”: CreateProcess error=2, ?????????
- at org.apache.hadoop.security.UnixUserGroupInformation.login(UnixUserGroupInformation.java:250)
- at org.apache.hadoop.security.UnixUserGroupInformation.login(UnixUserGroupInformation.java:275)
- at org.apache.hadoop.security.UnixUserGroupInformation.login(UnixUserGroupInformation.java:257)
- at org.apache.hadoop.security.UserGroupInformation.login(UserGroupInformation.java:67)
- at org.apache.hadoop.fs.FileSystem$Cache$Key.<INIT>(FileSystem.java:1353)
- at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:1289)
- at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:203)
- at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:108)
- at org.apache.hadoop.mapred.JobConf.getWorkingDirectory(JobConf.java:352)
- at org.apache.hadoop.mapred.FileInputFormat.setInputPaths(FileInputFormat.java:331)
- at org.apache.hadoop.mapred.FileInputFormat.setInputPaths(FileInputFormat.java:304)
- at org.apache.hadoop.examples.WordCount.run(WordCount.java:148)
- at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:65)
- at org.apache.hadoop.examples.WordCount.main(WordCount.java:159)
- Exception in thread “main” java.lang.RuntimeException: java.io.IOException
- at org.apache.hadoop.mapred.JobConf.getWorkingDirectory(JobConf.java:356)
- at org.apache.hadoop.mapred.FileInputFormat.setInputPaths(FileInputFormat.java:331)
- at org.apache.hadoop.mapred.FileInputFormat.setInputPaths(FileInputFormat.java:304)
- at org.apache.hadoop.examples.WordCount.run(WordCount.java:148)
- at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:65)
- at org.apache.hadoop.examples.WordCount.main(WordCount.java:159)
- Caused by: java.io.IOException
- at org.apache.hadoop.dfs.DFSClient.<INIT>(DFSClient.java:175)
- at org.apache.hadoop.dfs.DistributedFileSystem.initialize(DistributedFileSystem.java:68)
- at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:1280)
- at org.apache.hadoop.fs.FileSystem.access$300(FileSystem.java:56)
- at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:1291)
- at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:203)
- at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:108)
- at org.apache.hadoop.mapred.JobConf.getWorkingDirectory(JobConf.java:352)
- … 5 more
- Caused by: javax.security.auth.login.LoginException: Login failed: Cannot run program “whoami”: CreateProcess error=2, ?????????
- at org.apache.hadoop.security.UnixUserGroupInformation.login(UnixUserGroupInformation.java:250)
- at org.apache.hadoop.security.UnixUserGroupInformation.login(UnixUserGroupInformation.java:275)
- at org.apache.hadoop.dfs.DFSClient.<INIT>(DFSClient.java:173)
- … 12 more
运行的时候出现下面的错误,说/home/hadoop/HadoopInstall/tmp/mapred/system/job_200811260234_0022/job.xml的文件没找到
- 2008–12–10 21:26:48,680 INFO org.apache.hadoop.ipc.Server: IPC Server handler 0 on 9001, call submitJob(job_200811260234_0022) from 10.10.1.34:1328: error: java.io.IOException: /home/hadoop/HadoopInstall/tmp/mapred/system/job_200811260234_0022/job.xml: No such file or directory
- java.io.IOException: /home/hadoop/HadoopInstall/tmp/mapred/system/job_200811260234_0022/job.xml: No such file or directory
- at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:215)
- at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:149)
- at org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1155)
- at org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1136)
- at org.apache.hadoop.mapred.JobInProgress.<INIT>(JobInProgress.java:174)
- at org.apache.hadoop.mapred.JobTracker.submitJob(JobTracker.java:1755)
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
- at java.lang.reflect.Method.invoke(Method.java:597)
- at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:446)
- at org.apache.hadoop.ipc.Server$Handler.run(Server.java:896)
到server(hadoop主机)建立了system目录,依然错误,后来在高级选项中修改mapred.system.dir的属性仍然报错。最后通过
- conf.set(“mapred.system.dir”, “/home/hadoop/HadoopInstall/tmp/mapred/system/”);
运行成功,不过未明白高级设置中指定mapred.system.dir为什么无效。是plugin自身问题?
转载请注明:数据分析 » Hadoop上运行WordCount以及本地调试