四、MapReduce
4.1 概述
MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算。概念"Map(映射)“和"Reduce(归约)”,是它们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性。它极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。 当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一个共享相同的键组。
MapReduce
是Hadoop框架的一个并行计算框架
,将一个计算任务拆分成两个阶段:Map和Reduce
MapReduce计算框架充分利用了 存储节点(DataNode)所在物理主机的计算资源进行并行计算
默认情况下NodeManager会将本进程运行 的节点的计算资源抽像成8个计算单元,每个单元称之为一个Contioner
,所有的NodeManager都由ResourceManager调度,ResourceManager负责计算资源的统筹分配。
一是软件框架 二是并行处理 三 可靠容错 四 大规模计算 五 处理海量数据
MapReduce擅长做大数据处理,MapReduce的思想就是分而治之
-
Map负责**”分“**,即把庞大且复杂的任务分解成若干个”简单的任务“来处理,简单的任务包含三层
- 是对数据或者计算模型相对于原任务要大大缩小
- 就近计算原则,就是任务会被分配到存放所需数据的节点上进行计算
- 这些小任务不止一个且并行计算,而且彼此间没有依赖关系
-
Reducer负责对Map的计算结果进行汇总
4.2 为什么使用MR?
package com.baizhi.hdfs;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
public class CleanApp {
public static void main(String[] args) throws Exception {
File file = new File("G:\\Note\\Day02-Hadoop\\数据文件\\access.tmp2019-05-19-10-28.log");
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
FileWriter fileWriter = new FileWriter("G:\\Note\\Day02-Hadoop\\数据文件\\clean.log");
while (true) {
String line = bufferedReader.readLine();
if (line == null) {
bufferedReader.close();
fileWriter.close();
return;
}
boolean contains = line.contains("thisisshortvideoproject'slog");
if (contains) {
String s = line.split("thisisshortvideoproject'slog")[0];
fileWriter.write(s.trim() + "\n");
fileWriter.flush();
}
}
}
}
上述代码是对日志进行简单的清晰,在数据量少的时候一点问题都没有,但是数据量一旦增加,就可能无法胜任需求,因为无法在合理的时间内完成计算,此时单机性能已经成为计算的瓶颈,但是手写分布式应用程序难度太大,有现成的框架可以使用,那就是MR!
4.3 YARN 环境搭建
(1)什么是 YARN ?
Yarn作为一个资源调度平台,有一个全局的管理者叫做ResourceManager,ResourceManager负责对集群的整体计算及资源做统筹规划,有各个节点的管理者叫做NodeManager,负责向ResourceManager报告其计算资源的使用情况,在NodeManger中有一个MRAppMaster管理这里当前运行的MRApp,其任务是协调来自ResourceManager的资源,并与NodeManager一起执行和监视任务。
ResourceManager
:负责对集群的整体计算及资源做统筹规划
NodeManager
:管理主机上的计算组员,负责向RM 汇报自身的状态信息
MRAppMaster
:计算任务的Master,负责申请计算资源,协调计算任务
YARN Child
:负责做实际计算任务
Container:
计算资源的抽象单元
(2)配置YARN
etc/hadoop/yarn-site.xml
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<description>The hostname of the RM.</description>
<name>yarn.resourcemanager.hostname</name>
<value>HadoopNode00</value>
</property>
etc/hadoop/mapred-site.xml
etc/hadoop/ 下其实是没有这个文件 的但是有yitmp结尾的文件,将其改名即可
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
(3)启动YARN
[root@HadoopNode00 ~]# start-yarn.sh
starting yarn daemons
starting resourcemanager, logging to /home/hadoop/hadoop-2.6.0/logs/yarn-root-resourcemanager-HadoopNode00.out
localhost: starting nodemanager, logging to /home/hadoop/hadoop-2.6.0/logs/yarn-root-nodemanager-HadoopNode00.out
[root@HadoopNode00 ~]# jps
60192 Jps
60046 ResourceManager
60142 NodeManager
web 界面: hostname:8088
4.4 MR 入门程序
需求:
wangkai gjf zkf suns gzy
wangkai zkf suns gzy
zkf suns gzy hxz leijun
wangkai 2
gjf 1
zkf 3
suns 3
gzy 3
hxz 1
leijun 1
(1)依赖
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-jobclient</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>2.6.0</version>
</dependency>
(2)Mapper 逻辑
package com.baizhi.mr.test01;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/*
* keyIn LongWritable (Long) 输入文本字节偏移量
* valueIn Text (String) 输入文本行
* keyOut Text(String)
* valueOut IntWritable(Int)
* */
public class WCMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] names = value.toString().split(" ");
for (String name : names) {
context.write(new Text(name),new IntWritable(1));
}
}
}
(3)Reduce 逻辑
package com.baizhi.mr.test01;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/*
*keyIn Text 与mapper的keyOut的数据类型相对应
*valeuIn IntWritable 与mapper的ValueOut的数据类型相对应
* KeyOut
* valueOut
* */
public class WCReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
context.write(key, new IntWritable(sum));
}
}
(4)Job封装
package com.baizhi.mr.test01;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
public class JobRunner {
public static void main(String[] args) throws Exception {
/*
* 获取配置对象
* */
Configuration conf = new Configuration();
/*
* 获取Job对象
* */
Job job = Job.getInstance(conf);
/*
* 设置数据输入输出组件
* */
job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
/*
*设置数据输入输出路径
* */
TextInputFormat.setInputPaths(job, new Path("/wordcount.txt"));
/*
* 注意: 此输出路径不能存在
* */
TextOutputFormat.setOutputPath(job, new Path("/baizhi/out1"));
/*
* 设置MAP 和 REDUCE 处理逻辑
* */
job.setMapperClass(WCMapper.class);
job.setReducerClass(WCReducer.class);
/*
* 设置 map任务和reduce任务的输出泛型
* */
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 提交
//job.submit();
job.waitForCompletion(true);
}
}
4.5 部署运行
(1)远程Jar 包部署
// 设置jar 类加载器 否则MapReduce框架找不到Map和Reuce
job.setJarByClass(JobRunner.class);
- 打包
- 运行 hadoop jar 包的名字 主类名
[root@HadoopNode00 ~]# hadoop jar Hadoop_Test-1.0-SNAPSHOT.jar com.baizhi.mr.test01.JobRunner
(2)本地仿真
填坑
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
log4j.properties
### 配置根 ###
log4j.rootLogger = info,console
### 配置输出到控制台 ###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %p %d{yyyy-MM-dd HH:mm:ss} %c %m%n
(3)跨平台提交
- 需要拷贝相关配置文件到resource目录
- core-site.xml
- hdfs-site.xml
- yarn-site.xml
- mapred-site.xml
代码
System.setProperty("HADOOP_USER_NAME", "root");
conf.addResource("conf2/core-site.xml");
conf.addResource("conf2/hdfs-site.xml");
conf.addResource("conf2/mapred-site.xml");
conf.addResource("conf2/yarn-site.xml");
conf.set(MRJobConfig.JAR, "G:\\IDEA_WorkSpace\\BigData\\Hadoop_Test\\target\\Hadoop_Test-1.0-SNAPSHOT.jar");
配置跨平台提交
- 配置mapred-site.xml
<property>
<name>mapreduce.app-submission.cross-platform</name>
<value>true</value>
</property>
- 代码的方式
conf.set("mapreduce.app-submission.cross-platform", "true");