前言
- 对于没有接触过大数据技术的人来说,听到大数据这个名词可能会感到很陌生,会很疑惑大数据是个什么东西。
- 当年刚毕业的我就是这样。几年前刚毕业的时候,浏览各种招聘网站,难免会看到职位类型为大数据招聘信息,年轻的我就把它当作了某种高级程序员,也曾经对它有过憧憬,想着自己能不能成为一个大数据工程师呢。但是点进去看到各种不认识的编程语言后,当时只学过C,C#,Java,Python的我就望而却步了。
- 后来在工作中渐渐接触到Hadoop三大组件后,才对大数据有了自己一点浅显的理解。今天在这里给大家介绍一下Hadoop三大组件之一——MapReduce,带大家初始大数据的庐山真面目。
MapReduce整体架构图
1.概述
1.1 定义
MapReduce是一个分布式运算程序的编程框架
MapReduce的核心功能是 将用户编写的业务逻辑代码 和自带默认组件整合成一个完成的 分布式运算程序,并发运行在一个Hadoop集群上
1.2 优缺点
1.2.1 优点
- 易于编程。用户只关心业务逻辑。实现框架的接口
- 良好的扩展性:可以动态增加服务器,解决计算资源不够的问题
- 高容错性。任何一台机器挂掉,可以将任务转移到其他节点
- 适合海量数据计算(TB/PB),几千台服务器共同计算
1.2.2 缺点
1.不擅长实时计算 MySQL
2.不擅长流式计算 SparkStreaming flink
3.不擅长DAG有向无环图 spark graphx (基于内存)
1.3 核心编程思想
- MapReduce运算程序一般需要分成2个阶段:Map阶段和Reduce阶段
- Map阶段的并发MapTask,完全并行运行,互不相干
- Reduce阶段的并发ReduceTask,完全互不相干,但是他的数据依赖于上一个阶段的所有MapTask并发实例的输出
2.序列化
2.1 序列化概述
2.1.1 什么是序列化
序列化:把内存中的对象,转换成字节序列(或者其他数据传输协议)以便于存储到磁盘(持久化)和网络传输
反序列化:将字节序列或者是磁盘的持久化数据,转换成内存中的对象
2.1.2 为什么要序列化
序列化可以存储“活的”对象
2.1.3为什么不用java的序列化
java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(校验信息,Header,继承体系等),不便于在网络中高效传输
hadoop序列化框架只加上了简单的校验信息,因为是在系统内部传输,不需要那么多信息
- 好处
紧凑:存储空间少
快速:传输速度快
互操作性:跨语言传输
3.MapReduce框架原理
- shuffle中有 排序、分区、压缩、合并
- FileImputFormat实现类:TextInputFormat、CombineTextInputFormat、自定义InputFormat。以前还有(KeyValueTextInputFormat、LineInputFormat等等)
3.1 MapTask 并行度决定机制
- 数据块:Block 是 HDFS 物理上把数据分成一块一块。数据块是 HDFS 存储数据单位。
- 数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。数据切片是MapReduce程序计算输入数据的单位,一个切片会对应启动一个MapTask
3.2 FileInputFormat切片源码解析
-
程序先找到你数据存储的目录
-
开始遍历处理(规划切片)目录下的每一个文件
-
遍历第一个文件sm.txt
- 获取文件大小fs.sizeOf(sm.txt)
- 计算切片大小
computerSplitSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M mapreduce.input.fileinputformat.split.minsize=1默认值为1 mapreduce.input.fileinputformat.split.maxsize=Long.MAXValue 默认值Long.MAXValue
- 默认情况下,切片大小=blocksize
- 开始切片,形成第一个切片:sm.txt——0:128M 第二个切片——128:256M 第三个切片256:300M
每次切片时,都要判断切完剩下的部分是否大于块的1.1倍,不大于1.1被就划分一块新的切片
- 将切片信息写到一个切片规划文件中
- 整个切片的核心过程在getSplit()方法中完成
- InputSplit只记录了切片的元数据信息,比如起始位置、长度以及所在的节点列表等
-
提交切片规划文件到YARN上,YARN上的MrAppMaster就可以根据切片规划文件计算开启MapTask个数
切片机制
- 切片时不考虑数据集整体,而是针对每一个文件单独切片
3.3 获取切片信息API
//获取切片的文件名称
String name = inputSplit.getPath().getName();
//根据文件类型获取切片信息
FileSplit inputSplit = (FileSplit)context.getInputSplit();
3.4MapReduce详细工作流程
3.5 join
3.5.1 Reduce Join
- Map 端的主要工作:为来自不同表或文件的 key/value 对,打标签以区别不同来源的记
录。然后用连接字段作为 key,其余部分和新加的标志作为 value,最后进行输出。 - Reduce 端的主要工作:在 Reduce 端以连接字段作为 key 的分组已经完成,我们只需要
在每一个分组当中将那些来源于不同文件的记录(在 Map 阶段已经打标志)分开,最后进
行合并就 ok 了。
3.5.2 Map Join
3.5.2.1 使用场景
- Map Join 适用于一张表十分小、一张表很大的场景。
3.5.2.2 优点
- 在 Map 端缓存多张表,提前处理业务逻辑,这样增加 Map 端业务,减少 Reduce 端数
据的压力,尽可能的减少数据倾斜。
3.5.2.3 具体办法:采用 DistributedCache
- 在 Mapper 的 setup 阶段,将文件读取到缓存集合中。
- 在 Driver 驱动类中加载缓存。
//缓存普通文件到 Task 运行节点。
job.addCacheFile(new URI("file:///e:/cache/pd.txt"));
//如果是集群运行,需要设置 HDFS 路径
job.addCacheFile(new URI("hdfs://hadoop102:8020/cache/pd.txt"));
4. Hadoop 数据压缩
4.1 压缩优缺点
- 压缩的优点:以减少磁盘 IO、减少磁盘存储空间。
- 压缩的缺点:增加 CPU 开销。
4.2 压缩原则
- 运算密集型的 Job,少用压缩
- IO 密集型的 Job,多用压缩
4.3 MR 支持的压缩编码
压缩格式 | Hadoop 自带? | 算法 | 文件扩展名 | 是否可切片 | 换成压缩格式后,原来的 程序是否需要修改 |
---|---|---|---|---|---|
DEFLATE | 是,直接使用 | DEFLATE | .deflate | 否 | 和文本处理一样,不需要 修改 |
Gzip | 是,直接使用 | DEFLATE | .gz | 否 | 和文本处理一样,不需要 修改 |
bzip2 | 是,直接使用 | bzip2 | .bz2 | 是 | 和文本处理一样,不需要 修改 |
LZO | 否,需要安装 | LZO | .lzo | 是 | 需要建索引,还需要指定 输入格式 |
Snappy | 是,直接使用 | Snappy | .snappy | 否 | 和文本处理一样,不需要 修改 |