MapReduce是一个分布式计算框架。思想:将复杂问题分解成若干规模较小的部分,对每个部分进行逐个解决,再将每部分的结果进行合并得到最终结果。
Map阶段:对一组数据进行某种重复式的处理
Reduce阶段:对Map的中间结果进一步处理
Map和Reduce为两个抽象编程接口,由用户去编程实现:
map:(k1,v1)转换成(k2,v2)
reduce:(k2,[v2])转换成(k3,v3)
MapReduce特点:
- 易于编程,提供二次开发接口。但现在来说,Spark、Flink等计算框架更加容易与普遍,Spark吃内存,Flink吃CPU
- 良好的扩展性:可将计算节点增至成百上千,轻松处理TB级或PB级数据
- 高容错:一台节点宕机,计算任务会转移
- 适合海量数据离线处理
一个完整的MapReduce分布式运行时有三类:
- MRAppMaster:负责整个MR程序的过程调度及状态协调
- MapTask:负责map阶段的整个数据处理流程
- ReduceTask:负责reduce阶段的整个数据处理流程
阶段组成:
Map后面只能跟Reduce或者直接结束,不能多个Map相邻
执行MapReduce程序示例:
计算圆周率:
cd /export/server/hadoop-3.3.0/sbin #进入Hadoop文件夹
./start-all.sh#启动Hadoop集群
cd /export/server/hadoop-3.3.0/share/hadoop/mapreduce#进入示例文件夹
hadoop jar hadoop-mapreduce-examples-3.3.0.jar pi 2 2#启动计算圆周率的MR程序
单词计数WordCount编程思路:
1、map:数据切割并标记个数,输出格式[单词,1]
2、shuffle:把相同key分成一组
3、reduce:对每组的value进行累加得到每个单词的计数
首先,新建一个txt文件并上传到HDFS,并执行示例MR程序
hadoop jar hadoop-mapreduce-examples-3.3.0.jar wordcount /test /test/output
通过查看HDFS路径下 /test/output/part-r-00000文件来查看结果
MR内部执行流程:
1、Map流程**
- 将输入文件按照一定标准进行逻辑切片,默认切片大小和块大小一样(128M),每个切片由MapTask处理
- 对切片中数据按照规则读取返回key-value对,默认按行读取。key是每一行的起始文职偏移量,value是本行的文本内容。(TextInputFormat)
- 调用Mapper类中方法处理数据
- 按照一定规则对键值对进行分区partition
- Map输出写入内存,达到比例溢出写到磁盘上。溢出spill时候根据key进行排序
- 对溢出文件进行合并merge形成最终文件
2、Reduce流程
- ReduceTask主动从MapTask复制拉取自己要处理的数据
- 把拉到的数据进行merge合并并排序
- 对排序的key-value使用reduce,把键相等的放在一起最后写到HDFS中。
3、shuffle
在MR中,map输出之后到reduce输入之前为shuffle过程,即从无序到有序。shuffle的过程如下图。
map端shuffle:
- collect阶段:map结果输出到环形缓冲区,保存前对key进行Hash分区
- spill阶段:内存中数据达到阈值写入磁盘,写入磁盘前进行排序
- merge阶段:对溢出的临时文件进行合并,得到一个最终的输出数据
reduce端shuffle:
- copy阶段:reduce启动fetcher线程到已完成的节点上复制一份属于自己的数据
- merge阶段:在copy的同时,后台开启两个线程对内存到本地的数据文件进行合并操作
- sort阶段:merge同时进行排序操作,保证opy的数据整体有效性
4、代码编写MR程序
- 数据类型
2、配置Windows下环境变量
-
解压hadoop-3.3.0.tar.gz并配置环境变量,下载winutil 和 hadoop.ddl文件,下载地址:https://github.com/steveloughran/winutils/tree/master/hadoop-3.0.0/bin
-
将hadoop-3.3.0.tar.gz文件解压后,准备对应版本的hadoop.dll和winutils.exe文件,放到hadoop的斌文件夹,如:E:\learn\BigData\Hadoop\hadoop-3.3.0.tar\hadoop-3.3.0\bin
-
-
配置完成,双击winutil 文件无报错,在 cmd 输入"hadoop version",查看版本信息
报错图片
编辑hadoop-env.cmd文件
将
set JAVA_HOME=%JAVA_HOME%
修改为:
set JAVA_HOME=C:\PROGRA~1\Java\jdk1.8.0_144
3、编写程序
maven
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>${hadoop.version}</version>
</dependency>
- map程序
package MRDemo;
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;
public class TestMap extends Mapper<LongWritable, Text, Text, IntWritable> {
private Text t = new Text();
private IntWritable out=new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String s = value.toString();
String[] split = s.split(" ");
for (String s1 : split) {
t.set(s1);
context.write(t,out);
}
}
}
- reduce程序
package MRDemo;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class TestReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
IntWritable out=new IntWritable();
int sum=0;
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
for (IntWritable value : values) {
sum=sum+value.get();
}
out.set(sum);
context.write(key,out);
}
}
- 驱动程序(整合程序),将map和reduce连接起来
package MRDemo;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class TestMapReduce{
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(TestMapReduce.class);
job.setMapperClass(TestMap.class);
job.setReducerClass(TestReduce.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.setInputPaths(job,new Path("C:\\Users\\Administrator\\Desktop\\input\\test.txt"));
FileOutputFormat.setOutputPath(job,new Path("C:\\Users\\Administrator\\Desktop\\output"));
boolean result = job.waitForCompletion(true);
System.exit(result?0:1);
// job.submit();
}
}
其中输入数据为
hadoop spark hive
sqoop flink
hadoop hive
spark flink
输出数据为
flink 2
hadoop 4
hive 6
spark 8
sqoop 9
注意:输出的文件夹为不存在的文件夹,权限问题可在idea的虚拟机选项里-DHADOOP_USER_NAME=root