Hadoop-7-MapReduce
1、概述
MapReduce是一个分布式运算程序的框架,是用户开发基于Hadoop的数据分析应用的核心框架
MapReduce核心功能是将用户开发的业务逻辑和框架自带的组件整合成为一个完成的分布式运算程序,并将其运行在Hadoop集群上
2、优缺点
【1】优点
- 开发方便。只需继承一些组件类,就可以完成分布式程序,并且该程序可以在大量廉价的机器上运行
- 高扩展性。当集群资源不足时,可以方便地增加机器数量来提升集群的性能
- 高容错性。当某个节点宕机时,可以将该节点上计算任务转移到另外的节点上运行,并且这个过程是由Hadoop内部来完成的
- 海量数据的离线处理能力。MapReduce拥有对PB级别的数据进行处理的能力
【2】缺点
- 不能实时计算。MapReduce无法做到毫秒或秒级别的数据计算
- 无法流式计算。MapReduce要求输入的数据是静态的,而流式计算的数据是动态的
- DAG(Directed Acyclic Graph,有向无环图)计算效率较低。当多个MapReduce程序存在依赖关系时,即后一个程序的输入依赖前一个程序的输出。MapReduce会将每个Job的输出结果都存入磁盘,这样会需要大量的IO资源,导致性能很底下
3、核心思想
一个MapReduce job在执行的过程中,主要分为2个阶段:Map阶段和Reduce阶段
【1】Map阶段
首先将所有的输入目录里的文件读取到内存当中,分配好对应的MapTask,并按照Map阶段的程序逻辑执行这些任务。每个任务之间是相互独立的。当这些任务执行完毕后,再执行Reduce阶段
每个文件的读取次数取决于文件的大小和块(blocker)大小的设置。每个块,会执行一次Map(默认,详细查看 8、MapTask并行机制),而不是每个文件执行一次Map
【2】Reduce阶段
将Map阶段的输出结果,作为Reduce阶段的输入参数。分配好对应的ReduceTask,并一一执行它们。最终将结果输出到MapReduce程序指定的输出目录当中
一个MapReduce job只能有一个Map阶段和一个Reduce阶段,如果程序需要多个Map阶段和Reduce阶段,则只能编写多个MapReduce程序,并将它们串行运行
【3】MapReduce进程
一个完整的MapReduce程序在分布式运行时会有3类实例进程:
- MRAppMaster,负责整个程序运行过程中的资源调度和状态的协调
- MapTask,负责Map阶段的数据处理流程
- ReduceTask,负责Reduce阶段的数据处理流程
4、Hadoop序列化
因为Hadoop需要将不同节点上的内存里的数据进行网络传输,所以需要将这些数据进行序列化
Hadoop有自身所开发的高效的序列化方式,通过这种方式序列化后的数据将使用较少的字节(bytes)来表示
【1】常用Java类型所对应的Hadoop序列化类型
Java类型 | Hadoop序列化类型 |
---|---|
byte | ByteWritable |
short | ShortWritable |
int | IntWritable / VIntWritable(可变长度) |
long | LongWritable / VLongWritable(可变长度) |
float | FloatWritable |
double | DoubleWritable |
boolean | BooleanWritable |
String | Text |
null | NullWritable |
数组(Writable[]) | ArrayWritable |
Map<Writable, Writable> | MapWritable |
【2】自定义Hadoop序列化类型
定义步骤:
-
实现
org.apache.hadoop.io.Writable
接口 -
实现序列化方法
public void write(DataOutput dataOutput) throws IOException
和反序列化方法public void readFields(DataInput dataInput) throws IOException
注意序列化和反序列化的顺序必须保持一致
-
定义无参构造方法
-
如果想打印对象,还可以重写
toString
方法
注意:如果将自定义的对象作为KEY来使用时,则需要实现org.apache.hadoop.io.WritableComparable
接口,并实现int compareTo(T o)
方法。因为MapReduce框架在shuffle
时,会对KEY进行排序
以官方的IntWritable为例:
public class IntWritable implements WritableComparable<IntWritable> {
private int value;
public IntWritable() {
}
public IntWritable(int value) {
this.set(value);
}
public void set(int value) {
this.value = value;
}
public int get() {
return this.value;
}
public void write(DataOutput out) throws IOException {
out.writeInt(this.value);
}
public void readFields(DataInput in) throws IOException {
this.value = in.readInt();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof IntWritable)) {
return false;
} else {
IntWritable other = (IntWritable)o;
return this.value == other.value;
}
}
@Override
public int hashCode() {
return this.value;
}
@Override
public int compareTo(IntWritable o) {
int thisValue = this.value;
int thatValue = o.value;
return thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1);
}
@Override
public String toString() {
return Integer.toString(this.value);
}
static {
WritableComparator.define(IntWritable.class, new IntWritable.Comparator());
}
public static class Comparator extends WritableComparator {
public Comparator() {
super(IntWritable.class);
}
@Override
public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
int thisValue = readInt(b1, s1);
int thatValue = readInt(b2