大数据之八 hadoop MapReduce on YARN--WordCount

本文介绍了如何在YARN集群上配置并运行Hadoop MapReduce的经典案例WordCount。首先,详细讲述了YARN集群的配置步骤,然后在eclipse中配置MapReduce环境,接着详细解析了WordCount的map()、reduce()和main()方法的实现。最后,讨论了MapReduce的运行模式,包括本地运行和集群提交,并展示了如何在YARN上查看作业状态及HDFS上的输出结果。

前两篇中,我们了解了MapReduce的执行流程及其架构实现,今天我们就在本地通过经典实例WordCount来了解一下MapReduce的编程实现

YARN集群配置

  1. 首先我们按照大数据之四 hadoop HDFS HA 高可用的完全分布式搭建好集群环境,jps检查无误

  2. 关闭所有节点上的HDFS相关进程

  stop-dfs.sh
  1. 配置mapred-site.xml文件(cp mapred-site.xml.template mapred-site.xml
  <!-- MapReduce的架构体系,这里使用MapReduceV2,即YARN -->
  <property>
          <name>mapreduce.framework.name</name>
          <value>yarn</value>
  </property>
  1. 配置yarn-site.xml文件
    <!-- NodeManager上运行的附属服务。需配置成mapreduce_shuffle,才可运行MapReduce程序 -->
 	<property>
           <name>yarn.nodemanager.aux-services</name>
            <value>mapreduce_shuffle</value>
    </property>
    <property>
            <name>yarn.resourcemanager.ha.enabled</name>
            <value>true</value>			<!-- 启用RM的高可用 -->
    </property>
    <property>
            <name>yarn.resourcemanager.cluster-id</name>
            <value>cluster1</value>				<!-- YARN对外提供的服务的id -->
    </property>
    <property>
            <name>yarn.resourcemanager.ha.rm-ids</name>
            <value>rm1,rm2</value>			<!-- 实现RM高可用的节点id -->
    </property>
    <property>
            <name>yarn.resourcemanager.hostname.rm1</name>
            <value>node01</value>				<!-- rm1对应的真实节点 -->
    </property>
    <property>
            <name>yarn.resourcemanager.hostname.rm2</name>
            <value>node02</value>			  <!-- rm2对应的真实节点 -->
    </property>

	<!--配置三台zookeeper的位置信息 -->
    <property>
           <name>yarn.resourcemanager.zk-address</name>
           <value>node02:2181,node03:2181,node04:2181</value>
    </property>
  1. 将配置完成的hadoop安装包发送到其他节点,覆盖之前的安装包,也可以先删除之前的安装包
  scp -r hadoop-2.6.5 root@node02:/opt/zgl/
  scp -r hadoop-2.6.5 root@node03:/opt/zgl
  scp -r hadoop-2.6.5 root@node04:/opt/zgl/
  1. 在node01 或 node02 上启动HDFS
  start-dfs.sh
  1. 在node01 或 node02 上启动YARN,这里我们在node01上启动
  satrt-yarn.sh

因为 HDFS 和 YARN 都是hadoop的组件之一,这里步骤6,7可以用 start-all.sh 代替

  1. 启动后使用jps查看,成功的话node01节点上会启动ResourceManager进程,node02,node03,node04上会启动NodeManager进程。
[root@node01 ~]# jps
2390 NameNode
2726 DFSZKFailoverController
3111 Jps
2839 ResourceManager
2584 JournalNode

[root@node02 ~]# jps
2834 Jps
2706 NodeManager
2487 JournalNode
2393 DataNode
2571 DFSZKFailoverController
2268 QuorumPeerMain
2333 NameNode
  1. 这里我们会发现Node02上并没有启动standby状态的RM,这是因为系统默认就是不启动的,这里我们可以手动将其启动
  yarn-daemon.sh start resourcemanager

 [root@node02 ~]# jps
 3008 ResourceManager
 2706 NodeManager
 2487 JournalNode
 2393 DataNode
 2571 DFSZKFailoverController
 2268 QuorumPeerMain
 2333 NameNode
 3055 Jps
  1. YARN也提供Web UI来显示job相关信息,浏览器输入node01:8088。后面我们运行WordCount时,就可以在这里查看job状态
    job web UI

eclipse配置

更新客户端的hadoop安装包,按照 大数据之五 hadoop HDFS HA集群客户端+eclipse(java API)配置 对eclipse进行配置,确认其可以操作HDFS

打开Windows->Show View中的Map/Reduce Locations,右键选择Edit Hadoop location…
edit
在下图对MapReduce进行配置(确保node02上已启动RM)
MR Master
新建一个java项目,将hadoop安装包中share\hadoop目录下 common,hdfs,tools,yarn,mapreduce五个文件夹中的jar包及其下lib文件夹中的jar包整合导入项目并build path

将mapred-site.xml,yarn-site.xml文件拷贝到source文件夹中
source
接下来,我们就可以开始写代码了

WordCount

我们先来回顾一下MapReduce处理大数据集的过程
MR处理流程
做一些准备工作
首先我们在本地创建两个文本文件file1.txt和file2.txt,使file1.txt内容为"Hello World\nBye World",file2.txt的内容为"Hello Hadoop\nBye Hadoop"。
在HDFS 上创建输入文件夹 input,上传本地文件到集群的input 目录下

再来分析一下WordCount的执行过程

  1. 将文件拆分成splits,由于测试用的文件较小,所以我们写两个文件,每个文件为一个split,并将文件按行分割形成<key,value>对。这一步由MapReduce框架自动完成,其中偏移量(即key值)包括了回车所占的字节数
    split
  2. 将分割好的<key,value>对交给用户定义的map方法进行处理,生成新的<k2,v2>对
    map
  3. 得到map方法输出的<key,value>对后,Mapper会将它们按照key值进行排序分组,并执行Combine,将key至相同value值累加,得到Mapper的最终输出结果
    shuff write
  4. Reducer先对从Mapper接收的数据进行排序,再交由用户自定义的reduce方法进行处理,得到新的<k3,v3>对,并作为WordCount的输出结果
    reduce
    分析完执行过程,我们来看一下代码实现。
    要编程实现MapReduce计算,只需要继承Mapper类实现其map()方法,继承Reduce类实现其reduce()方法,并在main()函数中对job进行设置

序列化
因为HDFS涉及到序列化的问题,Hadoop的基本数据类型都实现了一个Writable接口,而实现了这个接口的类型都支持序列化。在Mapper类和Reducer类中都使用Hadoop自带的基本数据类型
序列化

map()

/**
     * @param KEYIN
     *            →k1 表示每一行的起始位置(偏移量offset)	LongWritable
     * @param VALUEIN
     *            →v1 表示每一行的文本内容	Text
     * @param KEYOUT
     *            →k2 表示每一行中的每个单词	Text
     * @param VALUEOUT
     *            →v2 表示每一行中的每个单词的出现次数,固定值为1	IntWritable
     */
public class WCMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
	Text myKey = new Text();	//设置Text类型的对象,用来封装KEYOUT,即k2
	IntWritable myValue = new IntWritable(1);	//设置IntWritable类型的对象并固定其值为1,即v2
	
	@Override
	protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
		System.out.println(key+"=========="+value);	//输出<k1,v1>值,这里的key为offset
		
		//使用hadoop自带的工具类StringUtil进行分词(按空格进行切割),相当于value.toString().split(" ")
		String[] words = StringUtils.split(value.toString(), ' ');
		
		//遍历分完的词,即k2,产生<k2,v2>,使用context进行输出。context是个上下文对象
		for (String word : words) {
			myKey.set(word);
			context.write(myKey,myValue);
		}
	}
}

reduce()

 /**
 * KEYIN     即K2     表示行中出现的单词 	Text
 * VALUEIN     即V2     表示出现的单词的次数 	IntWritable
 * KEYOUT     即K3     表示行中出现的不同单词	Text
 * VALUEOUT 即V3     表示行中出现的不同单词的总次数	IntWritable
*/
public class WCReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
	@Override
	protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
		//因为reduce处理的是“相同”key的一组数据,这里的key是真的相同,所以只要遍历v2累加计数即可
		 int sum = 0;
		 for (IntWritable value : values) {
			sum += value.get();
		}
		//输出<k3,v3>
		context.write(key, new IntWritable(sum));
	}
}

main()

public class WC {
	public static void main(String[] args) throws IOException,ClassNotFoundException, InterruptedException {
	
		//读取MapReduce配置信息,包括HDFS。设置为true则从本地项目source文件夹中读取配置文件
		Configuration conf = new Configuration(true);
		
		//构建一个job并指定job名称		
		Job job = Job.getInstance(conf,"WordCount");
		
		//设置当前main函数所在类
		job.setJarByClass(WC.class);
		
		//设置本地jar包位置 (第三种运行模式使用,另两种不用配置。运行模式在下面介绍)
		job.setJar("d:/mapreduce/wc.jar");
		
		//设置输入路径	args[0]表示参数手动输入
		FileInputFormat.setInputPaths(job, args[0]);
		
		//设置输出路径	这里路径写死,先判断路径下是否有文件,有则删除
		Path outputPath = new Path("/output/wordcount");
		FileSystem fs = outputPath.getFileSystem(conf);	
		if(fs.exists(outputPath)){
			fs.delete(outputPath,true);
		}
		FileOutputFormat.setOutputPath(job, outputPath);
		
		//设置Map class
		job.setMapperClass(WCMapper.class);
		
		//设置map输出key、value的类型
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);
		
		//设置reduce class
		job.setReducerClass(WCReduce.class);

		//设置reduce输出key、value的类型
		 job.setOutputKeyClass(Text.class);
         job.setOutputValueClass(IntWritable.class);
		
		//设置reduce task的个数 
		job.setNumReduceTasks(2);
		
		//提交作业
		job.waitForCompletion(true);
	}
}

main函数中主要做了如下几件事:
一是构建job,指定main函数所在类,指定输入、输出目录;
二是指定自定义的Mapper类和Reducer类及其对应输入输出key,value的类型;
三是提交作业

接下来我们就可以运行代码,运行前我们先来看几种运行模式
运行模式
1、local(在本地的eclipse上启动多个线程来模拟map task,reduce task执行,并未启动集群,所以YARN的job web UI页面不会有任务显示) ,用于测试环境
修改mapred-site.xml 中的mapreduce.framework.name,设置为local

<property>
	<name>mapreduce.framework.name</name>
	<value>local</value>
</property>

2、提交到集群中运行,用于生产环境
在本地将代码打成jar包,提交到集群。在集群上执行hadoop jar + jar包路径 + main()所在类的全类名 + 参数运行

[root@node01 mapreduce]# ls
wc.jar
[root@node01 mapreduce]# hadoop jar  ./wc.jar  com.hpe.mr.wc.WC  /input/*

3、在本机上的eclipse中直接提交任务到集群中运行,这里我们使用这种方式
(1) 修改配置文件 mapred-site.xml

	<property>
		<name>mapreduce.framework.name</name>
		<value>yarn</value>
	</property>
	<property>
		<name>mapreduce.app-submission.cross-platform</name>
		<value>true</value>			<!-- 跨平台提交开启 -->
	</property>

(2) 将本地Application打成jar包,放在window下某一个位置,这里放在D盘的mapreduce文件夹中
export
jar file
finish
ok

(3)右击项目,Run as --> Run Configurations
Run configurations

(4)点击Arguments,在Program arguments中填写参数,即我们在main()中写的args[0]的值,点击运行
arduments

(5)我们在console窗口可以看到我们在map中定义的<k1,v1>的输出

 0==========hello hadoop
 13==========bye hadoop
 0==========hello world
 12==========bye world`

(6)在node01:8088页面可以看到任务状态
TASK
(7)在HDFS上查看output/wordcount
HDFS
因为在main()中我们设置启动两个reduce task,所以最后输出两个文件part-r-00000和part-r-00001。
这里 bye world , world后面我不小心多加了个 ` ,所以最后结果是这样


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值