一、mapreduce诞生背景
(1) 海量数据在单机上处理由于硬件资源限制,无法胜任;
(2)将单机版程序扩展到集群来分布式运行,极大增加程序的复杂度和开发难度;
(3)引入MapReduce框架后,开发人员可以将绝大部分工作集中在业务逻辑的开发上,而将分布式计算中的复杂性交给框架来处理;
单机计算,需要使用cpu和内存(cpu核数包括内存的容量是有限的),如果要计算一个大文件,就会要很长的时间,比如说一个小时,所以提出了个概念,叫分布式计算(一台干不了的事情分成多台干,计算集群,),这个文件就需要分布式存储,问题是将来要对这个文件进行计算,计算任务需要启动到哪一台集群上,并行处理的话可能20分钟就计算完了,提高了计算的时间,另外一个问题,所有的及其已经处理完了各自的数据,那么处理完的结果如何汇总,如果引入到分布式来运行的话,是增加了程序的复杂度的,且开发难度也增加了。如果引入mapreduce框架之后,开发人员只需要负责业务开发,其他都交给框架完成。
单机计算(cpu和内存有限)→大文件耗时→提出分布式计算→涉及到计算任务启动的机器、计算后的结果汇总→引入mapreduce框架处理→开发人员则负责业务即可
二、mapreduce介绍
(1) MapReduce是一种分布式计算框架
(2) Doug Cutting根据《MapReduce: Simplified Data Processing on Large Clusters》设计实现了Hadoop中基于HDFS的MapReduce
(3) MapReduce是由两个阶段组成:Map和Reduce,用户只需要实现Map和Reduce两个方法编写业务逻辑,即可实现分布式计算,其目的在于简化分布式程序的开发和调试周期
(4) MapReduce的两个组件:
JobTracker/ResourceManager: 任务调度者,管理多个NodeManager,ResourceManager是Hadoop2.0版本后引入Yarn之后用于替代JobTracker部分功能的机制
TaskTracker/NodeManager: 任务执行者
数据是分布式存储到了服务器上,想对三块数据进行计算的时候是交给Map任务做,每一个Map任务处理每一块数据,处理完的结果,交给reduce阶段做最终的一个汇总。对于开发人员来说,map任务和reduce任务启动到哪一台服务器上,包括怎么读取数据块里的内容,都交给框架完成。开发人员负责业务的开发。
三、mapreduce处理流程
(1) mapreduce的核心思想:化大为小,分而治之。
mapreduce的主要组成部分:Mapper和Reducer
Mapper:负责“分”,即把复杂的任务分解成若干个“简单的任务”来处理
Reducer:负责对map阶段的结果进行汇总
以单词统计为例,了解mapper和reducer阶段做了什么事情:
四、mapreduce开发环境准备
首先启动hadoop集群,zookeeper。打开IDEA,创建一个Maven项目,选择jdk版本,模板原型选择quickstart(“Create from archetype”选择“maven-archetype-quickstart”)。单独创建个模块
在pom.xml中添加hadoop依赖包的坐标,添加依赖并刷新:
<dependency>
<groupid>org.apache.hadoop</groupid>
<artifactId>hadoop-client</artifactId>
<version>3.1.4</version>
</dependency>
需要把hadoop集群的两个配置文件导进来
hdfs-site.xml
core-site.xml
# 拷贝
scp core-site.xml root@ip地址:/headless/Desktop
scp hdfs-site.xml root@ip地址:/headless/Desktop
# 两个配置文件引入项目的resources资源目录下,为了识别hadoop集群,要操作hdfs中的数据文件,包括计算后的数据结果保存位置,需要识别两个配置文件
java目录右键com.yae.wordcount
五、mapreduce单词统计案例_mapper编写
package com.yae.wordcount;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
/*
* 继承hadoop写好的mapper类
* KEYIN : 定义map输入的key类型
* VALUEIN : 定义map输入的value类型
* KEYOUT : 定义map输出的key类型
* VALUEOUT : 定义map输出的value类型
* */
// 在hadoop中,long类型不能直接用,数据传输,比如数据从map阶段传输到reduce阶段,要求数据必须经过序列化,对long做了封装,用LongWritable;Text代表的string,IntWritable是对int做了封装,也是相当于对int进行序列化操作
// 定义泛型
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
// 重写map方法
@Override
//--每读取一行数据就会调用一次map方法
//--key : 行首偏移量
//--value : 一行数据
//--context : 是map及reduce的上下文对象,数据输出需要使用此对象
protected void map(LongWritable key, Text value, Mapper<LongWritable,Text,Text,IntWritable>.Context context) throws IOException, InterruptedException {
System.out.println("map方法执行了");
//按照分隔符进行切分,给每个单词打标记1,不能使用split方法,因为Text类型对象没有split方法,需要将value转换成toString类型,再进行切分
//line代表一行数据
String line = value.toString();
//--进行切分,按照空格 [hello world]
String [] words = line.split(" ");
//拿到了数组,然后遍历数组拿到每一个单词给打一个标记1
for (String word : words) {
//word是string类型,需要封装成Text,
context.write(new Text(word),new IntWritable(1));
}
}
}
六、mapreduce单词统计案例_reducer编写
package com.yae.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/*
* KEYIN: reduce输入key的类型——map输出的key的类型要一致
* VALUEIN: reduce输入的value的类型——map输出的value的类型一致
* KEYOUT: reduce输出的key的类型
* VALUEOUT: reduce输出的value的类型
* */
public class WordCountReducer extends Reducer <Text, IntWritable, Text, IntWritable>{
@Override
//重写reduce的方法
//key就是map输出的key,value是迭代器,对应的数据就是经过hadoop聚合后形成的value的数组,然后将数组输入到reduce,转换成迭代器
//只需要把迭代器中的数据进行遍历,拿到1进行累加,然后输出
//--每输入1个k,v对,就会调用一次。reduce调用的次数和有多少个单词有关系
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
System.out.println("reduce 方法执行了");
//--定义变量记录每个单词的总次数
int sum=0;
for (IntWritable value : values) {
int count = value.get();
sum+=count;
}
context.write(key, new IntWritable(sum));
}
}
七、mapreduce运行单词统计案例(明天补)
编写完mapper和reducer的逻辑,是独立的,需要将它们串起来变成mapreduce的工作任务,因此需要创建Job对象,在Job对象里定义要运行的mapper和Reducer以及要处理的文件和处理完的文件结果保存位置。此时创建一个入口类:
package com.yae.wordcount;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapreduce.Job;
import java.io.IOException;
public class WordCountDriver{
public static void main(String[] args) throws IOException {
//--定义一个配置文件对象,比如要存储的文件的副本数是多少,有点类似于配置文件,
Configuration conf = new Configuration();
//--创建job任务对象
Job.getInstance(conf,"wordcount");
}
}
参看视频:【【海牛大数据】Hadoop教程(Hadoop3.x从部署到优化全套讲解)】https://www.bilibili.com/video/BV1ed4y177zf?p=91&vd_source=24c4af34d5c7196f301016bf3b610c3f
PS:对于俺这样理解力很差的人来说,这个课讲的真的很容易理解,而且学着学着会觉得一些底层机制的东西没有之前看起来那么枯燥了,反而觉得很有趣,支持。