目录
一、 MapReduce
1.1 MapReduce定义
MapReduce是一种用于处理大规模数据集的编程模型和分布式运算程序的编程框架。它最初由Google公司开发,在后来成为了Apache Hadoop项目的核心组件之一。MapReduce的核心思想是将一个大的计算任务分解为多个可以并行执行的小任务,并通过将数据并行处理来实现高效的大规模数据处理。它适用于分布式环境下的数据处理,可以在大规模集群上并行执行计算任务,从而提高处理速度和可扩展性。
1.2 MapReduce优缺点
1.2.1 优点
- 简化编程模型
MapReduce提供了简单的编程接口,开发人员只需实现map和reduce函数即可,无需关注底层的并行和分布式细节。只需简单的实现一些接口,就可以完成一个分布式程序。 - 高可扩展性
MapReduce允许将大规模数据集分布在集群中进行处理,从而实现了高度可扩展性。可以通过增加集群中的节点数量来增加处理能力。 - 高容错性
MapReduce具有容错机制,当某个节点发生故障时,可以自动重新分配任务到其他可用节点上,保证任务的完成。 - 适用于大规模数据集
MapReduce适用于处理大规模的数据集,可以在分布式环境下高效地处理海量数据。
1.2.2 缺点
- 高延迟
由于MapReduce是批处理模型,需要等待所有任务完成后才能得到结果,因此对于实时性要求较高的场景不太适用。 - 适用性限制
MapReduce适用于批处理任务,但不适用于需要实时响应和交互式查询的场景。它主要适用于离线数据分析、批量处理和一次性计算等应用。 - 数据倾斜
在某些情况下,由于数据分布的不均匀,输入的数据可能会导致Reduce任务之间的负载不均衡,一些任务可能会比其他任务运行更长时间,从而影响整体性能。 - 不擅长DAG(有向无环图)计算
多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。
1.3 MapReduce核心思想
MapReduce的核心思想是将一个大的计算任务分解为多个可以并行执行的小任务,并通过将数据并行处理来实现高效的大规模数据处理。
具体而言,MapReduce模型包含两个主要的阶段:Map阶段和Reduce阶段。
在Map阶段,原始数据集会被划分成多个拆分的数据块,每个数据块会被分配给一个Map任务进行处理。Map任务接收输入数据,并将其转化为一系列中间键值对(key-value pairs)。
在Reduce阶段,Map任务输出的中间键值对会按照键进行排序和分区,并将相同键的键值对发送到同一个Reduce任务。Reduce任务负责对属于自己的中间键值对进行聚合并生成最终结果。
通过这种方式,MapReduce利用数据的并行处理能力,实现了高效的大规模数据处理和分析。每个小任务(Map任务)可以独立地处理自己分配到的数据块,而Reduce任务可以并行地对各个Map任务的输出进行聚合,从而加速整个计算过程。
注意:
1)第一个阶段的MapTask并发实例,完全并行运行,互不相干。
2)第二个阶段的ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。
3)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
1.4 MapReduce进程
一个完整的MapReduce程序在分布式运行时有三类实例进程:
(1)MrAppMaster:负责整个程序的过程调度及状态协调。
(2)MapTask:负责Map阶段的整个数据处理流程。
(3)ReduceTask:负责Reduce阶段的整个数据处理流程。
1.5 常用数据序列化类型
Java类型 | Hadoop Writable类型 |
---|---|
Boolean | BooleanWritable |
Byte | ByteWritable |
Int | IntWritable |
Float | FloatWritable |
Long | LongWritable |
Double | DoubleWritable |
String | Text |
Map | MapWritable |
Array | ArrayWritable |
Null | NullWritable |
1.6 MapReduce编程规范
用户编写的程序分成三个部分:Mapper、Reducer和Driver。
1.6.1Mapper阶段
WordCount官方代码截图:
- 用户自定义的Mapper要继承自己的父类Mapper
- Mapper的输入输出是KV键值对的形式(KV的类型可自定义)
- Mapper中的业务逻辑是写在map()方法中
- Mapper的输出数据是KV键值对的形式(KV的类型可自定义)
- map()方法对每一个<K,V>调用一次
1.6.2 Reduce阶段
WordCount官方代码截图:
- 用户自定义的Reducer要继承自己的父类
- Reducer的输入数据类型对应Mapper的输出数据类型
- Reducer的业务逻辑写在reduce()方法中
- ReduceTask进程对每一组相K的<K,V>组调用一次reduce()方法
1.6.3 Driver阶段
WordCount官方代码截图:
相当于Yarn集群客户端,用于提交我们整个程序到Yarn集群,提交的是封装了MapReduce程序相关运行参数的job对象。
1.7 WordCount案例实操
1.7.1 本地测试
(1)创建maven工程,并在pom.xml文件中添加如下依赖
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
(2)在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
(3)编写Mapper类
package com.amxl.mapreduce.wordcount;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
Text k = new Text();
IntWritable v = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 1 获取一行
String line = value.toString();
// 2 切割
String[] words = line.split(" ");
// 3 输出
for (String word : words) {
k.set(word);
context.write(k