07_MapReduce_深入浅出_note

MapReduce

1.1 分布式并行编程

  • 概述

    • MapReduce是一种分布式并行编程框架
    • cpu从05年便不再受摩尔定律控制,数据处理性能无法跟上爆发式增长的大数据
      • 数据处理能力提升的两条路线:
        • 单核CPU–>双核–>八核
        • 分布式并行编程
          • 借助一个集群通过多台机器同时并行处理大规模数据集
  • hadoop集成了MapReduce作为其两个核心组件之一

    • 解决分布式数据存储的HDFS
    • 解决分布式数据处理的Hadoop_MapReduce
  • 相关的并行编程框架:

    • MPI:消息传递接口,一种非常典型的并行编程框架
    • OpenCL
    • CUDA
    • FL(Federal Learning):一种基于机器学习的分布式并行框架。
  • MapReduce和传统的并行框架的区别

在这里插入图片描述

1.2 MapReduce模型简介

在这里插入图片描述

MapReduce的策略

	1. MapReduce采用分而治之
	2. 把非常庞大的数据集,切分成非常多的独立的小分片
	3. 为每一个数据分片单独地启动一个map任务
	4. 通过多个map任务,并行地在多个机器上处理

MapReduce的理念

  • 计算向数据靠拢,而不是数据向计算靠拢
    • 传统的计算方法–数据向计算靠拢:
      • 要完成一次数据分析时,选择一个计算节点,把运行数据分析的程序放到计算节点上运行
      • 然后把它涉及的数据,全部从各个不同的节点上拉过来,传输到计算发生的地方
        在这里插入图片描述
    • MapReduce–计算向数据靠拢
      在这里插入图片描述

Master/slave的架构

在这里插入图片描述

Map函数

在这里插入图片描述

Reduce函数

在这里插入图片描述


2.MapReduce体系结构

在这里插入图片描述

Client(客户端)

  • 通过Client可以提交用户编写的应用程序,用户通过Client将应用程序提交到JobTracker端
  • 通过Client提供的一些接口可以查看当前提交作业的运行状态

JobTracker(作业跟踪器)

  • 负责资源的监控和作业的调度
  • 监控底层的其他TaskTracker以及当前运行的Job健康情况
  • 一旦探测到失败的情况就把这个任务转移到其他节点,继续跟踪任务执行进度资源使用量

TaskTracker(任务调度器)

  • 执行具体的相关任务:一般接收jobTracker发送过来的命令并执行
  • 把自己的资源使用情况,以及任务的运行进度通过心跳*(heartbeat)*的方式发送给JobTracker

slot(槽)

  • 在MapReduce中有两种slot
    • Map类型的slot:供map任务使用
    • reduce类型的slot:供reduce任务使用
  • 两种slot无法相互转换
    • 如果有空闲的Map类型的slot,TaskTracke则把MapTask分配给该slot执行
    • 如果有空闲的reduce类型的slot,TaskTracke则把ReduceTask分配给该slot执行

Task(任务)

  • 任务有两种,都是由TaskTracker来启用的:

    • map任务
      • map函数
    • reduce任务
      • reduce函数
  • 在同一个机器下面,这两种任务可以同时处理


3. MapReduce工作流程

MapReduce工作流程概述

在这里插入图片描述

  • 注意:数据来源即输入(读操作)是HDFS,数据输出(写操作)也是在HDFS中
  • 不同的map()任务之间不会进行通信
  • 不同的Reduce()任务之间也不会进行通信

MapReduce各个执行阶段

在这里插入图片描述

分片(split)

  • InputFormat会把大的文件分割成很多个分片(split)
    在这里插入图片描述
  • 分片又会被HDFS分个大小不一的各个数据块block
  • 一般来说将一个HDFS数据块的大小作为分片的大小
  • 分片的个数就代表则需要并行处理多少个Map()任务

Reduce任务的数量

  • 最优的Reduce任务个数取决于集群中可用的reduce任务槽(slot)的数目

  • 通常设置比reduce任务槽数目少一些的Reduce任务个数(这样可以预留一些系统资源处理可能发生的错误)


4. shuffle过程原理

shuffle过程简介

在这里插入图片描述

  • 整个shuffle过程包含
    • Map端的shuffle
    • Reduce端的shuffle

Map端的shuffle过程

在这里插入图片描述

  1. 输入数据和执行map任务
    • 从HDFS读取数据(各种类型如.txt文件,二进制文件)
    • 将数据进行分片,将多个数据分片交给RecordReader处理
    • 通过RecordReader将数据的文件格式统一并输入这些数据到MapReduce的Map任务处理器进行处理
  2. 写入缓存
    • 对于每个Map任务,MapReduce都会分配一个默认的缓存(默认100M)给它使用
    • 缓存的作用是缓解寻址开销
    • 缓存一旦写满或到达某个设定门槛(溢写比),进入溢写进程
  3. 溢写
    • 分区
      • Map()任务输出的一堆键值对最终是交给多个不同的Reduce()任务处理的,所以要进行分区操作交由不同的Reduce()处理
      • 分区默认使用Hash函数
    • 排序
      • 分区后,系统会默认通过key来对各个分区的数据进行排序
    • 合并(combine)
      • 合并是为了减少溢写到磁盘当中的数据量
      • 如:自定义combine函数 {a:1}{a:2} --合并-> {a:3}
      • 这样的操作会减少很多的键值对,往磁盘写入的数据量就会大大减少
  4. 文件归并
    • 每次溢写都会生成一个磁盘文件,多次溢写后会生成一堆磁盘文件
    • 在整个Map()任务运行结束之前,系统会把这些溢写的磁盘文件进行归并成一个大的文件
    • 最后将这个大的文件放到本地磁盘中
    • JobTracker探测到文件归并进程结束,JobTracker就会通知相应的Reduce()任务把属于各自的分区数据拉走处理

Reduce端的shuffle过程

在这里插入图片描述

  • 归并数据
    • 是合并数据的逆向操作
    • 如{a:3}–归并–>{a,{1,2}}
    • 将map<k,v>转换为map<k,List>

5. MapReduce应用程序执行过程

在这里插入图片描述


6.实例分析:WordCount

WordCount程序任务

  • 输入:一个包含大量单词的文本文件

  • 输出:文件中每个单词出现次数,并按照单词字母顺序排序,每个单词和其词频占一行,单词和词频之间有间隔
    在这里插入图片描述

    在这里插入图片描述

  • 注意,只有满足可以分而治之的数据集才能用MapReduce进行处理,若数据集之间结果有强依赖,则无法利用Hadoop_MapReduce

WordCount设计思路

  • WordCount程序能不能用MapReduce去做?

    • Yes,可以把文本文件内容切分给多个Map任务,各自统计和排序。最后利用Reduce任务汇总
  • 若用户没有定义combine函数

    在这里插入图片描述
    在这里插入图片描述

  • 若用户定义了combine函数
    在这里插入图片描述


7. MapReduce具体应用

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


8. MapReduce编程实践

任务要求

在这里插入图片描述

分析

在这里插入图片描述

  • Map处理逻辑

    • 输入类型<key(行号),value(一行文本)>,即<Object,Text>

    • 输出类型<单词,单词出现次数>,如<Hadoop,1><Hello,1>,即<Text,IntWritable>

    • 自定义类MyMapper继承MapperReduce提供的Mapper类

      • 重写Mapper提供的map()函数,编写Map处理逻辑:

      在这里插入图片描述

  • Reduce处理逻辑

    • 输入类型<key,value-list>,key是单词Text类,value-list通过Iterable容器存储

    • 输出类型<key,value>,key是单词Text类,value是单词频率(IntWritable类)

    • 自定义MyReducer类继承MapReduce提供的Reducer类

      • 重写reduce()方法,编写reduce处理逻辑

    在这里插入图片描述

  • main函数

    在这里插入图片描述

  • 完整代码

    在这里插入图片描述

    在这里插入图片描述

import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;
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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
/**
 * 定义一个主类WordCount,用来描述job并提交job
 * 相当于一个Hadoop集群的客户端,
 * 需要在此封装我们的MapReduce程序相关运行参数,指定jar包
 * 最后提交给Hadoop
 * @author Administrator
 */

public class WordCount {
	public WordCount() {
	}

	public static void main(String[] args) throws Exception {
		// 1 获取配置信息,或者job对象实例
		Configuration conf = new Configuration();
		String[] otherArgs = (new GenericOptionsParser(conf, args)).getRemainingArgs();
		if (otherArgs.length < 2) {
			System.err.println("Usage: wordcount <in> [<in>...] <out>");
			System.exit(2);
		}
		Job job = Job.getInstance(conf, "word count");
		job.setJarByClass(WordCount.class);
		// 2 指定本业务job要使用的mapper/Reducer业务类
		job.setMapperClass(WordCount.TokenizerMapper.class);
		job.setCombinerClass(WordCount.IntSumReducer.class);
		job.setReducerClass(WordCount.IntSumReducer.class);
		// 3 指定最终输出数据的kv类型
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
		// 4 指定job的输入原始文件所在目录
		for (int i = 0; i < otherArgs.length - 1; ++i) {
			FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
		}
		FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length - 1]));
		
		System.exit(job.waitForCompletion(true) ? 0 : 1);
	}

	/**
	 * KEYIN:默认情况下,是MapReduce框架所读到的一行文本的起始偏移量,int;
	 * 在hadoop中有自己的更精简的序列化接口,所以不直接用Int,而是用IntWritable
	 * VALUEIN:默认情况下,是MapReduce框架所读到的一行文本内容,String;此处用Text
	 * KEYOUT:是用户自定义逻辑处理完成之后输出数据中的key,在此处是单词,String;此处用Text
	 * VALUEOUT,是用户自定义逻辑处理完成之后输出数据中的value,在此处是单词次数,Integer,此处用IntWritable
	 * 
	 * @author Administrator
	 */
	public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {
		private static final IntWritable one = new IntWritable(1);
		private Text word = new Text();

		public TokenizerMapper() {
		}

		/**
		 * map阶段的业务逻辑就写在自定义的map()方法中 maptask会对每一行输入数据调用一次我们自定义的map()方法
		 */
		public void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.Context context)
				throws IOException, InterruptedException {
			// 1 将maptask传给我们的文本内容先转换成String,并且利用工具类StringTokenizer根据空格将这一行切分成单词
			StringTokenizer itr = new StringTokenizer(value.toString());
			// 2 将单词输出为<单词,1>
			while (itr.hasMoreTokens()) {
				this.word.set(itr.nextToken());
				// 将单词作为key,将次数1作为value,以便于后续的数据分发,可以根据单词分发,以便于相同单词会到相同的reducetask中
				context.write(this.word, one);
			}
		}
	}

	/**
	 * KEYIN , VALUEIN 对应mapper输出的KEYOUT, VALUEOUT类型 
	 * KEYOUT,VALUEOUT 对应自定义reduce逻辑处理结果的输出数据类型 KEYOUT是单词 VALUEOUT是总次数
	 */
	public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
		private IntWritable result = new IntWritable();

		public IntSumReducer() {
		}
		/**
	     * key,是一组相同单词kv对的key
	     */
		public void reduce(Text key, Iterable<IntWritable> values,
				Reducer<Text, IntWritable, Text, IntWritable>.Context context)
				throws IOException, InterruptedException {
			int sum = 0;
			IntWritable val;
			// 1 汇总各个key的个数
			for (Iterator i$ = values.iterator(); i$.hasNext(); sum += val.get()) {
				val = (IntWritable) i$.next();
			}
			// 2输出该key的总次数
			this.result.set(sum);
			context.write(key, this.result);
		}
	}
}
  • 编译打包代码
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用Eclipse编译运行MapReduce程序

在Hadoop框架中执行MapReduce任务的几种方式

在这里插入图片描述


9. 一篇总结得比较好的博客

MapReduce入门


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设我们有一个天气数据集,每个记录包含日期、城市、最高温度和最低温度。我们想要统计每个城市在每个月的平均最高温度和平均最低温度,我们可以使用MapReduce进行分组统计。 首先,我们需要定义Mapper函数的输入和输出。Mapper函数的输入应该是文本行,每行表示一个天气记录,包含日期、城市、最高温度和最低温度,以逗号分隔。Mapper函数的输出应该是键值对,其中键是由城市和月份组成的复合键,值是一个包含最高温度和最低温度的可序列化对象。 伪代码如下: ```python Mapper(输入: key, value): 解析输入行,获取城市、日期、最高温度和最低温度 从日期中提取出月份 构造复合键,由城市和月份组成 构造值对象,包含最高温度和最低温度 发射键值对,以复合键为键,值对象为值 ``` 接下来,我们需要定义Reducer函数的输入和输出。Reducer函数的输入应该是键值对,其中键是由城市和月份组成的复合键,值是一个包含最高温度和最低温度的可序列化对象的迭代器。Reducer函数的输出应该是键值对,其中键是由城市和月份组成的复合键,值是一个包含平均最高温度和平均最低温度的可序列化对象。 伪代码如下: ```python Reducer(输入: key, values): 计算所有值的平均最高温度和平均最低温度 构造值对象,包含平均最高温度和平均最低温度 发射键值对,以复合键为键,值对象为值 ``` 最后,我们需要运行MapReduce作业。我们可以使用Hadoop Streaming工具,通过标准输入和输出来传递数据。假设我们的Mapper函数定义在mapper.py文件中,Reducer函数定义在reducer.py文件中,我们可以使用以下命令来运行作业: ```bash hadoop jar hadoop-streaming.jar \ -mapper mapper.py \ -reducer reducer.py \ -input input_file \ -output output_dir ``` 其中,hadoop-streaming.jar是Hadoop Streaming工具的JAR文件;mapper.py和reducer.py是我们定义的Mapper和Reducer函数;input_file是输入文件的路径;output_dir是输出目录的路径。 通过这种方式,我们可以使用MapReduce分组统计天气信息,并且可以方便地扩展到更大的数据集和更复杂的统计任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值