Hadoop生态圈(三):MapReduce

本文详细介绍了Hadoop MapReduce的核心概念、优缺点、编程规范以及工作流程。重点讲解了MapReduce的MapTask和ReduceTask的工作机制,包括数据输入、序列化、Shuffle过程、分区和排序。此外,还探讨了MapReduce的Join操作,包括Reduce Join和Map Join,并提供了案例分析。
摘要由CSDN通过智能技术生成

 

目录

1 MapReduce入门

1.1 MapReduce定义

1.2 MapReduce的优缺点

1.3 MapReduce核心思想

1.4 MapReduce进程(MR)

1.5 MapReduce编程规范

1.6 WordCount案例

2 Hadoop序列化

2.1 序列化概述

2.1.1 什么是序列化

2.1.2 为什么要序列化

2.13 为什么不使用java 的序列化Serializable

2.2 常用的数据序列化类型

2.3 自定义bean对象实现序列化接口(Writable)

2.4 序列化案例

3 MapReduce框架原理

3.1 MapReduce工作流程

3.2 InputFormat数据输入

3.2.1 FileInputFormat操作流程

3.2.2 FileInputFormat切片机制

3.2.3 CombineTextInputFormat案例

3.3 MapTask工作机制

3.3.1 并行度决定机制

3.3.2 MapTask工作机制

3.4 Shuffle机制

3.4.1 shuffle机制

3.4.2 Partition分区

3.4.3 partition分区案例

3.4.4  WritableComparable排序

3.4.5 WritableComparable排序案例

3.4.6 Combiner合并  

3.5 ReduceTask工作机制

3.6 MapReduce Join(关联)

3.6.1 Reduce Join

3.6.2 Reduce join案例

3.6.3 Map join


1 MapReduce入门

1.1 MapReduce定义

Mapreduce是一个分布式运算程序的编程框架,是用户开发“基于hadoop的数据分析应用”的核心框架。

Mapreduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个hadoop集群上。

1.2 MapReduce的优缺点

1. 优点

1.MapReduce 易于编程

它简单的实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行。就是因为这个特点使得MapReduce编程变得非常流行。

2.良好的扩展性

当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。

3.高容错性

MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由Hadoop内部完成的。

4.适合PB级以上海量数据的离线处理

它适合离线处理而不适合在线处理。比如像毫秒级别的返回一个结果,MapReduce很难做到。

2. 缺点

MapReduce擅长做实时计算、流式计算、DAG(有向图计算。

1. 实时计算

MapReduce无法像Mysql一样,在毫秒或者秒级内返回结果。

2. 流式计算

流式计算的输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化。这是因为MapReduce自身的设计特点决定了数据源必须是静态的。

3. DAG(有向图)计算

多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。

1.3 MapReduce核心思想

 

  1. 分布式的运算程序往往至少需要分为两个阶段
  2. 第一阶段的maptask并发实例,完全并行运行,互不相干
  3. 第二阶段的reudcetask并发实例互不相干,但是他们的数据依赖于上一个阶段所有maptask并发实例的输出
  4. MapReudce编程模型只能包含一个map阶段和reduce阶段,如果业务逻辑特别复杂,那就只能多个mapreduce程序串行执行

1.4 MapReduce进程(MR)

一个完整的mapreduce程序在分布式运行时有三类实例进程:

  1. MrAppMaster:负责整个程序的过程调度及状态协调。

  2. MapTask:负责map阶段的整个数据处理流程。

  3. ReduceTask:负责reduce阶段的整个数据处理流程。

1.5 MapReduce编程规范

用户编写的程序分为三个部分:Mapper、Reducer和Driver

  1. Map阶段:
    1. 用户自定义的Mapper要继承自己的父类
    2. Mapper的输入数据时KV对的形式(KV的数据类型可自定义)
    3. Mapper中的业务逻辑写在map()方法中
    4. Mapper的输出数据是KV对的形式(KV的数据类型可自定义)
    5. map()方法(maptask进程)对每一个<K,V>调用一次
  2. Reduce阶段:
    1. 用户自定义的Reducer要继承自己的父类
    2. Reducer的输入数据类型要对应Mapper的输出数据类型,也是KV格式的
    3. Reducer的业务逻辑写在reduce()方法中
    4. reducetask进程对每一组相同K的<K,V>组调用一次reduce方法
  3. Driver阶段(关联Mapper和Reducer,并且提交任务到集群)

相当于yarn集群的客户端,用于提交我们整个程序到yarn集群,提交的是封装了mapreduce程序相关运行参数的job对象

1.6 WordCount案例

1. 需求:dui下面给定的数中统计每一个单词出现的总次数

2. 需求分析:按照mapreduce规范,分别编写Mapper、Reducer、Driver

 

3. 准备工作

导入下面的依赖,配置文件

<dependencies>
    <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-client</artifactId>
        <version>2.7.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>2.7.2</version>
    </dependency>
</dependencies>

配置文件:

log4j.rootLogger=debug, 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

4. 编写程序

1. Mapper类

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 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[] strings = line.split(" ");
        //3.输出
        for (String string : strings) {
            k.set(string);
            context.write(k,v);
        }
    }
}

2.Reducer类

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{

    int sum;
    IntWritable v = new IntWritable();

    @Override
    protected void reduce(Text key, Iterable<IntWritable> value,
                          Context context) throws IOException, InterruptedException {

        // 1 累加求和
        sum = 0;
        for (IntWritable count : value) {
            sum += count.get();
        }

        // 2 输出
        v.set(sum);
        context.write(key,v);
    }
}

3.Driver类(注意导入的包是否正确)

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.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;

public class WordCountDriver {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        //1.获取配置信息及封装任务
        Configuration configuration = new Configuration();
        Job job = Job.getInstance(configuration);

        //2.设置jar加载路径
        job.setJarByClass(WordCountDriver.class);

        //3.设置map和reduce类
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordcountReducer.class);

        //4.设置map输出
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //5.设置reduce输出
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //6.设置输入输出的路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        //7.提交
        job.waitForCompletion(true);
    }
}

4. 本地测试

需要在window上配置HADOOP_HPME的环境变量,然后再IDEA上运行

5. 集群测试

  1. 将程序打jar包,上传到hadoop集群
  2. 启动hadoop集群,运行wordcount程序

[hadoop@hadoop101 software]$ hadoop jar  wordcount.jar  com.bigdata.wordcount.WordcountDriver /user/hadoop/input  /user/bigdata/output1         //上传的jar的名称,驱动类的包名+类名,输入路径,输出路径

2 Hadoop序列化

2.1 序列化概述

2.1.1 什么是序列化

序列话就是将内存中的对象,转换成字节序列(或者其他的传输协议)以便于存储(持久化)和网络传输

反序列化就是将收到的字节序列(或其他的传输协议)或者磁盘上持久化的数据。转换为内存中的对象

2.1.2 为什么要序列化

一般来说,“活的”对象只生存在内存里,关机断电就没有了。而且“活的”对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机。 然而序列化可以存储“活的”对象,可以将“活的”对象发送到远程计算机。

2.13 为什么不使用java 的序列化Serializable

java的序列化是一个重量级序列化框架,一个对象被序列化后,会附带很多额外的信息(各种校验,herder,继承体系等),不便于在网络中高效的传输。所以hadoop自己开发了一套序列化机制(Writable),有以下特点:

紧凑:紧凑的格式能让我们充分利用网络带宽,而网络带宽是数据中心最稀缺的资源

快速:进程通信形成了分布式系统的骨架,所以需要尽量减少序列化和反序列化的性能开销

互操作:能支持不同语言写的客户端和服务端进行交互

2.2 常用的数据序列化类型

常用的数据类型对应的hadoop数据序列化类型

Java类型

Hadoop Writable类型

boolean

BooleanWritable

byte

ByteWritable

int

IntWritable

float

FloatWritable

long

LongWritable

double

DoubleWritable

String

Text

map

MapWritable

array

ArrayWritable

2.3 自定义bean对象实现序列化接口(Writable)

自定义bean对象要想序列化传输,必须实现序列化接口,必须注意以下事项:

  1. 必须实现Writable接口
  2. 反序列化时,需要反射调用空参构造函数,所以必须有空参构造
  3. 重写序列化方法
  4. 重写反序列化方法
  5. 注意反序列化的顺序要和序列化的顺序一致
  6. 要想把结果显示在文件中,需要重写toString()方法,可用 “\t” 分开,方便后续调用

2.4 序列化案例

1. 需求: 统计每一个手机号耗费的总上行流量、下行流量、总流量

输入数据格式:

1363157993055     13560436666    C4-17-FE-BA-DE-D9:CMCC     120.196.100.99     18     15      1116          954      200

                             手机号码                                                                                                  上行流量    下行流量

输出数据格式

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值