Hadoop3.x

Hadoop

一、Hadoop入门

重点内容:

Hadoop入门
	1、重点理解Hadoop的优势(需结合Hadoop的组成)
	2、完全分布式运行模式
	> xsync 集群分发脚本
	> ssh无密登录配置(必须配置,重点记忆)
	3、常用端口号
	hadoop3.x 
		HDFS NameNode 内部通常端口:8020/9000/9820
		HDFS NameNode 对用户的查询端口:9870
		Yarn查看任务运行情况的:8088
		历史服务器:19888
	hadoop2.x 
		HDFS NameNode 内部通常端口:8020/9000
		HDFS NameNode 对用户的查询端口:50070
		Yarn查看任务运行情况的:8088
		历史服务器:19888
	4、常用的配置文件
		3.x core-site.xml  hdfs-site.xml  yarn-site.xml  mapred-site.xml workers
		2.x core-site.xml  hdfs-site.xml  yarn-site.xml  mapred-site.xml slaves

课上笔记:


5、面试重点:hadoop 的组成
	---> hadoop1.x  2.x  3.x 版本区别(了解)
	5.1 HDFS架构概述(数据存储)
		NameNode:存储文件的元数据
		DataNode:在本地文件系统存储文件块数据以及块数据的校验和。
	5.2 YARN架构概述(资源调度)
		常驻:
		ResouceManager:所有资源的管理者和分配者
		NodeManager:单个节点服务器管理
		临时:
		applicationMaster:单个任务运行的老大
		container:

	5.3 MapRenduce架构概述(计算)
	
虚拟机  环境变量配置()
 sudo touch 文件名.sh
 sudo vim 文件名.sh
 
 6、ssh rsync   -p
 ssh 底层是TCP,ssh是在TCP的基础上,对信息加密后进行传输,即密文
6.1  ssh免密登录(必须配置)
 ssh-keygen -t rsa  生成公钥私钥对  回车三次
 公钥也要给自己一份  ssh-copy-id 自己的主机名
 (如出现yes输错,无法会退的情况,按Ctrl + 回退)
 
7、集群的规划
7.1 老大不要放在一起,小弟越多越好
hdfs有 nn   dn   2nn,老大 nn
yarn有  rm  dm,老大 rm
虚拟机无法ping外网的问题(netservice 问题)
---> 原因:网卡未成功启动。
---> 解决方法:见下图

在这里插入图片描述

1、 大数据概述

1、1 大数据可以做什么?

解决海量数据的采集、存储、分析计算问题。
数据存储单位一般为TB、PB、EB等。

补充了解:
分布式存储(同一数据源多地存储)
分布式计算(多人共同完成一个计算)

1、2 大数据的特点(4V)

大量 volume
高速 velocity
多样 variety 结构化数据/非结构化数据
低价值密度 value 数据提纯

2、 Hadoop

2、1 Hadoop是什么?可以做什么?

Hadoop是一个分布式系统基础框架,可以解决海量数据的存储、分析计算问题。

Hadoop通常指的是更广泛的概念 — 即 Hadoop生态圈。

2、2 Hadoop 三大发行版本(需知道)

(1)Apache:最原始(最基础)的版本,适于入门学习,于2006年发布

(2)Cloudera:内部集成了很多大数据框架,对应产品CDH,于2008年发布

(3)Hortonworks:文档较好,对应产品HDP,于2011年发布

​ 目前该版本已被Cloudera收购,推出了CDP

2、3 Hadoop的优势(4高)

存储优势:

高可靠性:体现在Hadoop底层维护了多个数据副本
高扩展性:在集群间分配任务数据,方便扩展更大数量的节点

计算优势:

高效性:Hadoop中包含MapReduce框架,可以使Hadoops并行工作,从而加快任务处理速度
高容错性:能够自动将失败的任务进行重新分配(也是基于MapReduce),失败分配有上限

2、4 Hadoop 的组成

2、4、1 首先了解下Hadoop的版本区别:

Hadoop1.x / Hadoop2.x / Hadoop3.x
在这里插入图片描述

2、4、2 框架详解:
(1)HDFS框架(数据存储)

Hadoop Distributed File System 分布式文件系统

1)nn(NameNode):存储文件的元数据以及每个文件的块列表 和块所在的DataNode等

2)dn(DataNode):在本地文件系统存储文件块数据以及块数据 的校验和

3)2nn(SecondaryNameNode):每隔一段时间对NameNode 元数据备份

(2)Yarn框架(资源调度)

资源调度
常驻:
ResouceManager:所有资源的管理者和分配者
NodeManager:单个节点服务器管理
临时:
applicationMaster:单个任务运行的老大
container:容器

1)RM(ResourceManager):整个集群资源(内存、CPU等)的老大

2)NM(NodeManager):单个节点服务器资源老大

3)AM(ApplicationMaster):单个任务运行的老大

4)Container:容器,相当一台独立的服务器,里面封装了任务运行所需要的资源。如内存、CPU、磁盘、网络等

(3)MapReduce框架(计算)

MapReduce将计算过程分为两个阶段:Map和Reduce

Map 并行计算

Reduce 汇总Map结果

2、4、3 三者是怎么工作的?(需理解)

在这里插入图片描述

2、5(重点)Hadoop运行模式之完全分布式运行模式

本地运行模式(测试可用,一般不用)

伪分布式模式(忽略)

2、5、1 运行环境配置
2、5、2 集群配置
2、5、3 ssh配置

ssh-keygen -t rsa

解释这句命令:

ssh-keygen

[-q] 安静模式

[-b bits] 位数

[-t dsa | ecdsa | ed25519 | rsa | rsa1] 加密算法

ssh-keygen — 身份验证密钥的生成,管理和转换

使用-t选项指定要生成的密钥的类型

查看生成的密钥:

[root@localhost .ssh]# ls ~/.ssh/   或者  在ssh目录下ls
id_rsa  id_rsa.pub  known_hosts
各文件含义:
id_rsa   私钥
id_rsa.pub    公钥
known_hosts   记录ssh访问过计算机的公钥
authorized_keys   存放授权过的无密登录服务器公钥

(4)Web端查看HDFS的NameNode

(a)浏览器中输入:http://hadoop102:9870

​ (b)查看HDFS上存储的数据信息

(5)Web端查看YARN的ResourceManager

(a)浏览器中输入:http://hadoop103:8088

(b)查看YARN上运行的Job信息

HDFS

1、HDFS是什么?使用场景?优缺点?

HDFS是一种分布式文件管理系统。

使用场景:一次写入,多次读出

优点:

​ > 高容错性(多个副本)

​ > 适合处理大数据

​ > 可以构建在廉价(相对)机器上

缺点:

​ > 不适合低延时数据访问(量大,无法即时存下来)

​ > 不能用于小文件存储

​ > 不支持并发写入、文件随机修改,仅支持数据append

2、HDFS的组成

在这里插入图片描述

总结
NameNode:管理者

(1)管理HDFS的名称空间
(2)配置副本策略
(3)管理数据块Block映射信息
(4)处理客户端读写请求

DataNode:作为Slave。nn下达命令,dn执行实际的操作

(1)存储实际的数据块
(2)执行数据块的读写操作

​Client:客户端

(1)文件切分。
文件上传HDFS的时候,Client将文件切分成一个一个的BLock,然后进行上传
(2)与nn交互,获取文件的位置信息
(3)与dn交互,读取或写入数据
(4)Client提供一些命令来管理HDFS,比如NN格式化
(5)Client可以通过一些命令来访问HDFS,比如对HDFS增删查改操作

​2nn:辅助(定期合并数据,并推送给nn。紧急情况下可以辅助恢复nn)

(1)辅助nn,分担器工作量,比如定期合并Fsimage和Edits,并推送给nn
(2)在紧急情况下,可辅助恢复nn

3、HDFS 文件块大小(重点,要记)

块大小不能设置太大,也不能太小,默认128m
记住:HDFS块的大小设置主要取决于磁盘传输速度
在这里插入图片描述

思考:为什么块的大小不能设置太小,也不能设置太大?
(1)HDFS的块设置太小,会增加寻址时间,程序一直在找块的开始位置;
(2)如果块设置的太大,从磁盘传输数据的时间会明显大于定位这个块的开始位置所需的时间。导致程序在处理这块数据时,会非常慢。

硬盘读写速度:
在企业中 一般128m(中小公司) 256m (大公司)

4、HDFS的命令操作(重点)

hdfs dfs 或者 hadoop fs 可以查看所有命令

准备工作:

需要启动hadoop集群:
	sbin/start-dfs.sh
	sbin/start-yarn.sh
输出命令参数:
	hadoop fs -help rm
创建一个测试用文件夹
	hadoop fs -mkdir /name

(1)上传:

-put 等同于copyFromLocal(常用)

-appendToFile 追加一个文件到已经存在的文件末尾

-moveFromLocal 从本地剪切粘贴到hdfs (一般不用)

-copyFromLocal 从本地文件系统中拷贝文件到hdfs路径中

(2)下载

-get 等同于copyToLocal (常用)

-copyToLocal 从hdfs拷贝到本地

(3)直接操作

-ls 显示目录信息

-cat 显示文件内容

-mkdir 创建路径

-cp 从hdfs的某个路径拷贝到hdfs的另一个路径

-mv 在hdfs中移动文件

-tail 显示一个文件的末尾1kb的数据

-rm 删除文件或文件夹

-rm-r 递归删除目录及目录里的内容

-du 统计文件夹的大小信息

-chgrp \ -chmod \ -chown 修改文件所属权限

-setrep 设置hdfs中文件的副本数量(但是实际的副本数要看dn的数量)

5、HDFS 的API操作

5.1 客户端环境准备

配置HADOOP_HOME 环境变量
配置PATH环境变量

5.2 实例练习

新建maven工程,添加依赖(坐标+日志)

<dependencies>
	<dependency>
		<groupId>org.apache.hadoop</groupId>
		<artifactId>hadoop-client</artifactId>
		<version>3.1.3</version>  和服务器版本一致
	</dependency>
</dependencies>

6、HDFS 的读写流程(重点,理解+记忆)

6.1 写数据

6.1.1 写数据流程

在这里插入图片描述
(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
(2)NameNode返回是否可以上传。
(3)客户端请求第一个 Block上传到哪几个DataNode服务器上。
(4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
(5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
(6)dn1、dn2、dn3逐级应答客户端。
(7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
(8)当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。

6.1.2 网络拓扑 - 节点距离计算

节点的选择遵循两点:省资源(近) 安全
在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据,计算 :节点距离:两个节点到达最近的共同祖先的距离总和。

6.1.3 机架感知(副本存储节点选择)

在这里插入图片描述

6.2 读数据流程

在这里插入图片描述
(1)客户端通过DistributedFileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。

7、nn 2nn

7.1 nn 2nn的工作机制

理解:2nn 到底服务了什么(— 数据汇总)
思考:NameNode中的元数据是存储在哪里的?
首先,我们做个假设,如果存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并

7.2 nn 工作机制

在这里插入图片描述
1)第一阶段:NameNode启动
(1)第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode记录操作日志,更新滚动日志。
(4)NameNode在内存中对元数据进行增删改。
2)第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
(2)Secondary NameNode请求执行CheckPoint。
(3)NameNode滚动正在写的Edits日志。
(4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint。
(7)拷贝fsimage.chkpoint到NameNode。
(8)NameNode将fsimage.chkpoint重新命名成fsimage。

7.3 Fsimage和Edits解析

在这里插入图片描述
1)oiv查看Fsimage文件
(1)查看oiv和oev命令

[atguigu@hadoop102 current]$ hdfs
oiv            apply the offline fsimage viewer to an fsimage
oev            apply the offline edits viewer to an edits file

(2)基本语法
hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
(3)案例实操

[atguigu@hadoop102 current]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/name/current

[atguigu@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml

[atguigu@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/fsimage.xml

将显示的xml文件内容拷贝到Idea中创建的xml文件中,并格式化。部分显示结果如下。

<inode>
	<id>16386</id>
	<type>DIRECTORY</type>
	<name>user</name>
	<mtime>1512722284477</mtime>
	<permission>atguigu:supergroup:rwxr-xr-x</permission>
	<nsquota>-1</nsquota>
	<dsquota>-1</dsquota>
</inode>
<inode>
	<id>16387</id>
	<type>DIRECTORY</type>
	<name>atguigu</name>
	<mtime>1512790549080</mtime>
	<permission>atguigu:supergroup:rwxr-xr-x</permission>
	<nsquota>-1</nsquota>
	<dsquota>-1</dsquota>
</inode>
<inode>
	<id>16389</id>
	<type>FILE</type>
	<name>wc.input</name>
	<replication>3</replication>
	<mtime>1512722322219</mtime>
	<atime>1512722321610</atime>
	<perferredBlockSize>134217728</perferredBlockSize>
	<permission>atguigu:supergroup:rw-r--r--</permission>
	<blocks>
		<block>
			<id>1073741825</id>
			<genstamp>1001</genstamp>
			<numBytes>59</numBytes>
		</block>
	</blocks>
</inode >

思考:可以看出,Fsimage中没有记录块所对应DataNode,为什么?
在集群启动后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。

7.4 CheckPoint时间设置 (1小时 100万次)

1)通常情况下,SecondaryNameNode每隔一小时执行一次。
[hdfs-default.xml]

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600s</value>
</property>

2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。

<property>
  <name>dfs.namenode.checkpoint.txns</name>
  <value>1000000</value>
<description>操作动作次数</description>
</property>

<property>
  <name>dfs.namenode.checkpoint.check.period</name>
  <value>60s</value>
<description> 1分钟检查一次操作次数</description>
</property>

8、DataNode

8.1 DataNode工作机制

在这里插入图片描述
(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的块信息。
DN向NN汇报当前解读信息的时间间隔,默认6小时;

<property>
	<name>dfs.blockreport.intervalMsec</name>
	<value>21600000</value>
	<description>Determines block reporting interval in milliseconds.</description>
</property>

DN扫描自己节点块信息列表的时间,默认6小时

<property>
	<name>dfs.datanode.directoryscan.interval</name>
	<value>21600s</value>
	<description>Interval in seconds for Datanode to scan data directories and reconcile the difference between blocks in memory and on the disk.
	Support multiple time unit suffix(case insensitive), as described
	in dfs.heartbeat.interval.
	</description>
</property>

(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
(4)集群运行中可以安全加入和退出一些机器。
总结
.meta 数据长度单放chunk,校验和、时间戳放在.meta
dn启动后(第一次)会向nn汇报一次。之后每周期(6小时)汇报一次,内容为所有块信息。
心跳(3秒一次),如果10分钟+30秒(默认的超时时长)没有收到返回,则认为该节点不可用

8.2 数据完整性

思考:如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理DataNode节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?
如下是DataNode节点保证数据完整性的方法。
(1)当DataNode读取Block的时候,它会计算CheckSum。
(2)如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
(3)Client读取其他DataNode上的Block。
(4)常见的校验算法crc(32),md5(128),sha1(160)
(5)DataNode在其文件创建后周期验证CheckSum。
在这里插入图片描述
思考:什么情况会验证数据的完整性?
上传时
每6小时
下载
思考:如何验证完整性?
常见的校验方法有三种:
crc(32)
md5(128)
shal(160)
数字越高,安全性越高

### 	8.3	掉线时限参数设置
![在这里插入图片描述](https://img-blog.csdnimg.cn/a6df162611e6411685856f9970b1af06.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBATG9yZWV0YQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。
dfs.namenode.heartbeat.recheck-interval 300000 dfs.heartbeat.interval 3 ``` # MapReduce ### 重点内容:
三、Map Reduce
	1、InputFormat
		1)默认的是TextInputformat  kv  key偏移量,v :一行内容
		2)处理小文件CombineTextInputFormat 把多个文件合并到一起统一切片
	2、Mapper 
		setup()初始化;  map()用户的业务逻辑; clearup() 关闭资源;
	3、分区
		默认分区HashPartitioner ,默认按照key的hash值%numreducetask个数
		自定义分区
	4、排序
		1)部分排序  每个输出的文件内部有序。
		2)全排序:  一个reduce ,对所有数据大排序。
		3)二次排序:  自定义排序范畴, 实现 writableCompare接口, 重写compareTo方法
			总流量倒序  按照上行流量 正序
	5、Combiner 
		前提:不影响最终的业务逻辑(求和 没问题   求平均值)
		提前聚合map  => 解决数据倾斜的一个方法
	6、Reducer
		用户的业务逻辑;
		setup()初始化;reduce()用户的业务逻辑; clearup() 关闭资源;
	7、OutputFormat
		1)默认TextOutputFormat  按行输出到文件
		2)自定义

课上笔记:

1、MapReduce是什么
2、序列化
3、MR 框架原理
MR工作机制(重点理解记忆)
shuffle的流转
maptask工作机制(各阶段分析理解)
3、MR编程核心思想:
...ReduceTask  必须等MapTask 完全结束后,才可以运行...
4、MR进程
5、数据序列化类型
	---> 注意一点: 只是改变了类型的称呼,没有修改API,所以使用时需要先转为JAVA,处理后再转为MP
6、MR编程规范(三个阶段)
	MapReduce
	Reduce
	Driver:job
7、提交到集群测试
	补充:如何从windows的ideal中发送至集群运行?(详见文件---windows上向集群提交任务)
	注意:driver类中
		 (1)该设置要在job设置之前
		 (2)路径和用户信息 需要“造假”
		 (3)添加jar包
8、序列化
	为什么要进行序列化?----将信息存储在本地
	首先回顾java的序列化(4步)
	
	输出流 -- write  -- 序列化
	输入流 -- read  -- 反序列化
	
	hadoop的序列化实现:
	dataInput 序列化
	dataOutput   反序列化
	注意:序列化和反序列化的属性顺序是一致的
	>>(1)实现writable接口
	  (2)空参构造(必须有)
	  (3)get  set
	  (4)重写write  read方法(注意属性的顺序一致)
	  (5)如果需要在文件中显示结果,需要再重写toString方法
	  (6)如果需要按照Key排序,还需实现comparable接口
	实例解析:
	(1)Bean类中   定义属性,实现writable接口(重写read  writer 方法)
	(2)重写toString
	(3)Mapper类中   继承Mapper,传入参数  text flowBean,重写map方法
	(4)Reduce类中  继承类,传入参数 text  FlowBean   text  FlowBean,重写reduce方法
	
9、MR框架原理(难点)
	MR 流程
	(1)数据块和数据切片
	切片:
	---> (切片只是逻辑上操作),每个切片就是一个Maptask,即切片数量完全等于map数量
Job提交流程源码 /  切片源码
FileInputFormat切片机制:常用 TextInputFormat和CombineTextInputFormat(处理小文件过多的情况)

> CombineTextInputFormat   先存储再组合
	> 自定义切片大小 size
	> 小于size,划分一块
	> 大于size  小于 2*size, 切片大小 = 大小除以2
	> 大于size  且 大于 2*size,先切一块size,剩下的再按上面判断,再切一块size或者直接除以2切片

10、MR详细工作流程
10.1 map + sort
环形缓冲区:默认大小100M,到达80% 后触发拟写,反向追加
	---  两个数据  左边是索引,定位数据位置,排索引比排数据快  右边是数据---快排
分区内数据有序(区内有序)
同一map中多次逆写,会在某个时间点将两个文件合并,归并排序--- 归并怎么做 
10.2 copy + sort + reduce
10.3 shuffle   最主要做的是排序   提前合并
	 combiner:合并 combiner为可选,并非必走,可多次combiner,溢出,归并做3次
	 
11、实例操作
provinceParttition 类
传入参数 Text  FlowBean
重写getpartition方法
		---  转化字符串
		---  获取前三位
		---  进行比较给与分区号
driver类
	---	设置使用分区器
	---	设置reduce个数  由reduce个数决定分区号,并按序排列,当reduce个数设置为1,不会报错,所有数据放到一个文件中(不走分区)
	分区规则总结:
	---(1) reducetask数量决定了分区号
			例 数量为5,分区号为 0 1 2 3 4
	---(2) reducetask数量超过返回分区号(对应不上)  会有reduce空转,造成资源浪费
	---(3) reducetask数量小于分区号且不为1,运行报错
	---(4) reducetask数量为1,不会走分区,所有数据放在一个文件中
	---(5) 只有reducetask的数量刚好等于分区号,资源最优
	
ReduceTask 工作机制(reducetask个数?数据倾斜?)

WritableComparable排序
(1)默认按照key排序,这里的key为mapper输出key
(2)排序分类:部分排序/全排序/二次排序   ---常用
			 辅助排序(以后讲)
			 
combiner
(1)能用就用
		优点:减少IO、避免数据倾斜、
(2)使用前提:存在reducer

Outputformat的自定义(一般不会用,了解即可)

MR内核源码解析

MapReduce

1、MR概述

1.1 什么是MapReduce?MapReduce可以做什么?

是一个分布式运算程序的编程框架

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

1.2 MR优缺点

优点:

(1)易于编程

​ (通过简单的实现一些接口,就可以完成一个分布式程序)

(2) 良好的扩展性

(通过增加机器来拓展计算资源)

(3) 高容错性

(Hadoop内部可以自行完成 当某机器挂了时,将其正在进行的计算任务转移至其他节点继续运行 的处理)

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

(可实现服务器集群并发工作)

缺点:

(1)不擅长实时计算(指的是结果返回不能实时)

(2) 不擅长流式计算(不能进行流式计算)

(3) 不擅长DAG(有向无环图)计算(应用程序间存在依赖关系,即 前一个的输出是后一个的输入。如果有环,每个MR的输出结果都需要写入磁盘,造成大量磁盘IO,导致性能低下)

1.3 MapReduce核心思想:

在这里插入图片描述
(1)分布式的运算程序往往需要分成至少2个阶段。
(2)第一个阶段的MapTask并发实例,完全并行运行,互不相干。
(3)第二个阶段的ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。
(4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
总结:分析WordCount数据流走向深入理解MapReduce核心思想。

总结分为两个部分:Map Reduce

(1)Map阶段:并行计算

(2)Reduce阶段:汇总处理

ReduceTask的数据依赖MapTask的输出,所以必须等MapTask 完全结束后,才可以运行

MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户业务逻辑复杂,只能多个MR程序,串行运行。

1.4 MR进程(三个实例进程)

一个完整的MapReduce程序在分布式运行时有三类实例进程:
(1)MrAppMaster:负责整个程序的过程调度及状态协调

(2)MapTask:负责Map阶段的整个数据处理流程

(3)ReduceTask:负责Reduce阶段的整个数据处理流程

1.5 数据序列化类型

在这里插入图片描述
注意一点: 只是改变了类型的称呼,没有修改API,所以使用时需要先转为JAVA,处理后再转为MR

1.6 MR编程规范(三个部分)重点

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

(1)Mapper

1)自定义的Mapper类继承父类Mapper

2)Mapper输入数据和输出数据都是KV对,类型自定义

3)重写map方法,写业务逻辑,MapTask进程对每个KV对调用一次

(2)Reducer

1)自定义的Reducer继承父类Reducer

2)输入、输出数据类型和Mapper一致,也是KV对

3)重写reduce方法

4)Reduce进程对每一组相同k的键值对调用一次reduce()方法

(3)Driver (job)

相当于Yarn集群客户端,用于提交整个程序至Yarn集群,提交的是封装了MR程序相关运行参数的job对象

1.7 WordCount案例实操

1.7.1 数据准备

需求:在给定的文本文件中统计输出每一个单词出现的总次数
在这里插入图片描述
在这里插入图片描述

1.7.2 环境准备

(1)创建maven工程,MapReduceDemo
(2)在pom.xml文件中添加如下依赖

<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.1.3</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.30</version>
    </dependency>
</dependencies>

(2)在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。

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

(3)创建包名:com.atguigu.mapreduce.wordcount

1.7.3 编写程序

(1)编写Mapper类

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

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

(2)编写Reducer类

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

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

int sum;
IntWritable v = new IntWritable();

	@Override
	protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
		
		// 1 累加求和
		sum = 0;
		for (IntWritable count : values) {
			sum += count.get();
		}
		
		// 2 输出
         v.set(sum);
		context.write(key,v);
	}
}

(3)编写Driver驱动类

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

public class WordCountDriver {

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

		// 1 获取配置信息以及获取job对象
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);

		// 2 关联本Driver程序的jar
		job.setJarByClass(WordCountDriver.class);

		// 3 关联Mapper和Reducer的jar
		job.setMapperClass(WordCountMapper.class);
		job.setReducerClass(WordCountReducer.class);

		// 4 设置Mapper输出的kv类型
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);

		// 5 设置最终输出kv类型
		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
		boolean result = job.waitForCompletion(true);
		System.exit(result ? 0 : 1);
	}
}

5)本地测试
(1)需要首先配置好HADOOP_HOME变量以及Windows运行依赖
(2)在IDEA/Eclipse上运行程序

1.7.4 集群上测试
(1)用maven打jar包,需要添加打包插件依赖
<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
//注意:如果工程上显示红叉。在项目上右键->maven->Reimport刷新即可。
(2)Maven中点击package完成打包

​ 思考(用带依赖的jar包还是不带依赖的? 这里集群上已有环境,使用的是不带依赖的jar包)

(3)拷贝jar包至hadoop3.1.3的路径下
(4)启动集群,并运行程序
已配置的情况下:myhadoop.sh start
或
[atguigu@hadoop102 hadoop-3.1.3]sbin/start-dfs.sh
[atguigu@hadoop103 hadoop-3.1.3]$ sbin/start-yarn.sh
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop jar  wc.jar
 com.atguigu.mapreduce.wordcount.WordCountDriver /user/atguigu/input /user/atguigu/output

补充:如何从windows的ideal中发送至集群运行?(详见文件—windows上向集群提交任务)
注意:driver类中
(1)该设置要在job设置之前
(2)路径和用户信息 需要“造假”
(3)添加jar包

2、MR之Hadoop序列化(重点+理解)

2.1 序列化是什么?为什么要进行序列化?

序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。
反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象。
序列化可以存储“活的”对象,可以将“活的”对象发送到远程计算机。

 把内存对象 要么落盘 要么进行传输给到其他机器上进行使用(反序列化)
 序列化主要序列化什么内容 --- 序列化你的类的属性 所谓的数据
 序列化的本质是什么? ---  将内存中的内容落盘就是输出流(序列化)
                        将磁盘中的内容加载到内容中就是输入流(反序列化)

思考:为什么不用Java的序列化?
Java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,Header,继承体系等),不便于在网络中高效传输。所以,Hadoop自己开发了一套序列化机制(Writable)。

2.2 hadoop序列化特点:

(1)紧凑

​ — 高效使用存储空间

(2)快速

​ — 读写数据的额外开销小

(3)互操作

​ — 支持多语言交互

输出流 -- write  --- 写入磁盘、网络传输 --- 序列化
输入流 -- read  --- 转换成内存中的对象 --- 反序列化

2.3 hadoop的序列化实现

了解:定义一个javabean需要的步骤是什么(4大步)

实现Serializable 接口
私有的属性
空参构造器
私有的属性提供get和set方法
ObjectOutputStream 里面的writeObject(obj) 进行序列化
ObjectInputStream 里面的readObject 进行反序列化

hadoop和java的序列化的差异:

java 属性 头信息 继承体系 与各个框架的兼容性
hadoop 里面 属性 头信息(校验和) 内容会少一点

2.3.1 自定义bean对象实现序列化接口(Writable)6个步骤:

(1)实现writable接口
(2)反序列化时,需要反射调用空参构造函数,所以必须有空参构造

public FlowBean() {
	super();
}

(3)get set
(4)重写write(dataInput 反序列化) read(dataOutput 序列化)方法注意:序列化和反序列化的属性顺序是一致的

序列化
@Override
public void write(DataOutput out) throws IOException {
	out.writeLong(upFlow);
	out.writeLong(downFlow);
	out.writeLong(sumFlow);
}
反序列化
@Override
public void readFields(DataInput in) throws IOException {
	upFlow = in.readLong();
	downFlow = in.readLong();
	sumFlow = in.readLong();
}

(5)如果需要在文件中显示结果,需要再重写toString方法,用“\t“分开
(6)如果需要按照Key排序,还需实现comparable接口(Shuffle过程的map阶段有一对kv,方法 map<key,val,key,val>,第二个key必须能够实现排序)

@Override
public int compareTo(FlowBean o) {
	// 倒序排列,从大到小
	return this.sumFlow > o.getSumFlow() ? -1 : 1;
}

2.3.2 序列化的实例解析:

步骤:

(1)需求分析 输入数据格式 输出数据格式

(2)Map阶段

1、读取一行数据,切分字段

2、抽取输出数据: 手机号 上行流量 下行流量

3、以手机号为key,bean对象为value输出。即context.write(手机号,bean)

4、bean对象要想能够传输,必须实现序列化接口,即实现writable接口(重写read writer 方法)

(3)Reduce阶段

计算总流量 ,上行流量 和 下行流量 的累加值

对应到类中:

(1)Bean类中

1、类实现writable接口(需重写read write方法)

2、类的空参构造(给后续反射用)

3、在重写read 和 write方法前,需要先定义属性 (上行流量、下行流量、总流量)

这里根据手机号,设置数据类型为long

4、属性的get set方法

5、这里setSumFlow方法需要重载,无参方法,sum = up + down

6、重写read 和 write方法,注意序列化和反序列化的顺序必须一致

7、重写toString方法,“\t”

(2)mapper类中

1、类继承Mapper<输入K,输入V,输出K,输出V>

泛型分析:

输入K 默认的输入格式TextInputFormat产生的键类型是LongWritable

输入V Text(传入一行数据,类似字符串)

输出K Text

输出V javaBean(Bean中包含上行流量、下行流量、总流量)

2、需重写map方法

— 获取一行数据

String line = value.toString();

— 对获取的数据按照分隔符“\t”进行分割,用String[]保存

String[] split = line.split("\t");

— 根据数组下标获取所需的数据(手机号、上行流量、下行流量)

— 对数据进行封装 (set方法)

这里outk outV定义为类的私有变量

outK–Text

outV–javaBean

— 写出数据 context.write(outK,outV)

(3)reducer类中

1、类继承Reducer<>

输入KV 和map的输出类型一致,即<Text,FlowBean>

这里输出类型和输入一致

2、重写reduce方法

通过循环累加upFlow和down Flow

3、封装数据

这里reducer的输入key是存在的,即map的输出,不需要再次定义

定义 outV,FlowBean类型

4、写出数据 context.write(key,outV)

(4)driver类中

固定写法:

1、获取job

Job.getInstance()

2、设置jar

job.setJarByClass()

3、关联Mapper和Reducer

job.setMapperClass()

job.setReducerClass()

4、设置map端的输出KV类型

job.setMapOutputKeyClass()

job.setMapOutputValueClass()

5、设置程序最终输出的KV类型

job.setOutputKeyClass()

job.setOutputValueClass()

6、设置程序的输入、输出路径

FileInputFormat.setInputPaths()

FileOutputFormat.setOutputPath()

7、提交job

boolean b = job.waitForCompletion(true);

System.exit(b ? 0 : 1);

3、MR框架原理(重点、难点)

在这里插入图片描述

(1)按照阶段分类:MapTask 阶段 和 ReduceTask 阶段

业务逻辑:

map(MapTask)阶段:

(1)根据数据源input选择数据处理方式(默认按行读取数据)

(2)组件inputFormat,对输入控制,其他有如FileInputFormat、TextInputFormat、CombineTextInputFormat等,实现类有很多处理方式来读取数据源

(3)数据源读取后,交给Mapper进行数据逻辑处理

在Mapper和Reducer阶段之间还存在shuffle阶段,该阶段可以进行排序、分区、压缩等,是MR的核心阶段

reducer(ReduceTask)阶段:

(1)Reducer主动获取Mapper处理后的数据进行处理

(2)处理完后,需要确定输出到哪里,通过outputFormat处理

(2)按照数据流方向:

InputFormat —> Shuffle —> OutputFormat

详细一点: inputFormat(读取数据)—maptask —shuffle — reducetask(默认为1) — outputFomat

(3)从源码上看: inputformat(读取数据)–>map+sort–>copy+sort+reduce–>outputformat(结果写出)

3.1 MR详细工作流程

在这里插入图片描述

inputFormat(读取数据)—maptask —shuffle — reducetask(默认为1) — outputFomat

3.1.1 map + sort

环形缓冲区:默认大小100M,到达80% 后触发溢写(反向溢写),反向追加,存放两个数据

​ — 左边是索引,默认大小1M ,定位数据位置,排索引比排数据快

​ — 右边是数据,默认大小100M,—分区快排
溢写到文件,(文件)分区内数据有序(区内有序)
同一map中多次逆写,会在某个时间点将两个文件合并,归并排序— 归并怎么做

3.1.2 copy + sort + reduce
3.1.3 shuffle 最主要做的是分区、排序

​ combiner:合并 combiner为可选,并非必走,溢写超3次,还需进行combiner

(1)常说的shuffle 其实就是 Map的sort+Reduce的copy+sort

(2)InputFormat中主要有两个方法:生成切片getSplits + 读取方法createRecordReader

(3)Outputformat中主要方法:写出方法getRecordWriter

3.2 InputFormat数据输入

数据块和数据切片

切片:
​ —> (切片只是逻辑上操作),每个切片就是一个Maptask,即切片数量完全等于map数量
Job提交流程源码 / 切片源码
FileInputFormat切片机制:常用 TextInputFormat和CombineTextInputFormat(处理小文件过多的情况)

CombineTextInputFormat 先存储再组合
自定义切片大小 size
小于size,划分一块
大于size 小于 2size, 切片大小 = 大小除以2
大于size 且 大于 2
size,先切一块size,剩下的再按上面判断,再切一块size或者直接除以2切片

3.2.1 切片和MapTask并行度决定机制

1)问题引出
MapTask的并行度决定Map阶段的任务处理并发度,进而影响到整个Job的处理速度。
思考:1G的数据,启动8个MapTask,可以提高集群的并发处理能力。那么1K的数据,也启动8个MapTask,会提高集群性能吗?MapTask并行任务是否越多越好呢?哪些因素影响了MapTask并行度?
2)MapTask并行度决定机制
数据块:Block是HDFS物理上把数据分成一块一块。数据块是HDFS存储数据单位。
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。数据切片是MapReduce程序计算输入数据的单位,一个切片会对应启动一个MapTask。
在这里插入图片描述

3.2.2 Job提交流程源码和切片源码详解

1)Job提交流程源码详解

waitForCompletion()

submit();

// 1建立连接
	connect();	
		// 1)创建提交Job的代理
		new Cluster(getConfiguration());
			// (1)判断是本地运行环境还是yarn集群运行环境
			initialize(jobTrackAddr, conf); 

// 2 提交job
submitter.submitJobInternal(Job.this, cluster)

	// 1)创建给集群提交数据的Stag路径
	Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf);

	// 2)获取jobid ,并创建Job路径
	JobID jobId = submitClient.getNewJobID();

	// 3)拷贝jar包到集群
copyAndConfigureFiles(job, submitJobDir);	
	rUploader.uploadFiles(job, jobSubmitDir);

	// 4)计算切片,生成切片规划文件
writeSplits(job, submitJobDir);
		maps = writeNewSplits(job, jobSubmitDir);
		input.getSplits(job);

	// 5)向Stag路径写XML配置文件
writeConf(conf, submitJobFile);
	conf.writeXml(out);

	// 6)提交Job,返回提交状态
status = submitClient.submitJob(jobId, submitJobDir.toString(), job.getCredentials());

在这里插入图片描述
FileInputFormat切片源码解析(input.getSplits(job))
在这里插入图片描述

3.2.3 FileInputFormat切片机制

3.2.3.1 切片机制
(1)简单的按照文件的内容长度进行切片
(2)切片大小,默认等于Block大小
(3)切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
3.2.3.2 FileInputFormat切片大小的参数配置

3.2.4 TextInputFormat

1)FileInputFormat实现类
思考:在运行MapReduce程序时,输入的文件格式包括:基于行的日志文件、二进制格式文件、数据库表等。那么,针对不同的数据类型,MapReduce是如何读取这些数据的呢?
FileInputFormat常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、NLineInputFormat、CombineTextInputFormat和自定义InputFormat等。
2)TextInputFormat
TextInputFormat是默认的FileInputFormat实现类。按行读取每条记录。键是存储该行在整个文件中的起始字节偏移量, LongWritable类型。值是这行的内容,不包括任何行终止符(换行符和回车符),Text类型。
以下是一个示例,比如,一个分片包含了如下4条文本记录。

Rich learning form
Intelligent learning engine
Learning more convenient
From the real demand for more close to the enterprise

每条记录表示为以下键/值对:

(0,Rich learning form)
(20,Intelligent learning engine)
(49,Learning more convenient)
(74,From the real demand for more close to the enterprise)
3.2.5 CombineTextInputFormat切片机制

框架默认的TextInputFormat切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下。
1)应用场景:
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理。
2)虚拟存储切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。
3)切片机制
生成切片过程包括:虚拟存储过程和切片过程二部分。
在这里插入图片描述
(1)虚拟存储过程:
将输入目录下所有文件大小,依次和设置的setMaxInputSplitSize值比较,如果不大于设置的最大值,逻辑上划分一个块。如果输入文件大于设置的最大值且大于两倍,那么以最大值切割一块;当剩余数据大小超过设置的最大值且不大于最大值2倍,此时将文件均分成2个虚拟存储块(防止出现太小切片)。
例如setMaxInputSplitSize值为4M,输入文件大小为8.02M,则先逻辑上分成一个4M。剩余的大小为4.02M,如果按照4M逻辑划分,就会出现0.02M的小的虚拟存储文件,所以将剩余的4.02M文件切分成(2.01M和2.01M)两个文件。
(2)切片过程:
(a)判断虚拟存储的文件大小是否大于setMaxInputSplitSize值,大于等于则单独形成一个切片。
(b)如果不大于则跟下一个虚拟存储文件进行合并,共同形成一个切片。
(c)测试举例:有4个小文件大小分别为1.7M、5.1M、3.4M以及6.8M这四个小文件,则虚拟存储之后形成6个文件块,大小分别为:
1.7M,(2.55M、2.55M),3.4M以及(3.4M、3.4M)
最终会形成3个切片,大小分别为:
(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M

3.3 MapReduce工作流程

在这里插入图片描述
在这里插入图片描述
上面的流程是整个MapReduce最全工作流程,但是Shuffle过程只是从第7步开始到第16步结束,具体Shuffle过程详解,如下:
(1)MapTask收集我们的map()方法输出的kv对,放到内存缓冲区中
(2)从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件
(3)多个溢出文件会被合并成大的溢出文件
(4)在溢出过程及合并的过程中,都要调用Partitioner进行分区和针对key进行排序
(5)ReduceTask根据自己的分区号,去各个MapTask机器上取相应的结果分区数据
(6)ReduceTask会抓取到同一个分区的来自不同MapTask的结果文件,ReduceTask会将这些文件再进行合并(归并排序)
(7)合并成大文件后,Shuffle的过程也就结束了,后面进入ReduceTask的逻辑运算过程(从文件中取出一个一个的键值对Group,调用用户自定义的reduce()方法)
注意:
(1)Shuffle中的缓冲区大小会影响到MapReduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快。
(2)缓冲区的大小可以通过参数调整,参数:mapreduce.task.io.sort.mb默认100M。

3.4 OutputFormat数据输出

在这里插入图片描述

3.5 Shuffle机制

在这里插入图片描述

3.5.1 partition分区

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

3.5.2 WritableComparable排序

在这里插入图片描述
排序概述:
在这里插入图片描述
排序分类:
在这里插入图片描述
自定义排序WritableComparable原理分析
bean对象做为key传输,需要实现WritableComparable接口重写compareTo方法,就可以实现排序。

@Override
public int compareTo(FlowBean bean) {

	int result;
		
	// 按照总流量大小,倒序排列
	if (this.sumFlow > bean.getSumFlow()) {
		result = -1;
	}else if (this.sumFlow < bean.getSumFlow()) {
		result = 1;
	}else {
		result = 0;
	}

	return result;
}
3.5.3 Combiner合并

在这里插入图片描述

3.6 MapReduce内核源码解析

3.6.1 MapTask工作机制

在这里插入图片描述
(1)Read阶段:MapTask通过InputFormat获得的RecordReader,从输入InputSplit中解析出一个个key/value。
(2)Map阶段:该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value。
(3)Collect收集阶段:在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用Partitioner),并写入一个环形内存缓冲区中。
(4)Spill阶段:即“溢写”,当环形缓冲区满后,MapReduce会将数据写到本地磁盘上,生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。
溢写阶段详情:
步骤1:利用快速排序算法对缓存区内的数据进行排序,排序方式是,先按照分区编号Partition进行排序,然后按照key进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照key有序。
步骤2:按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N表示当前溢写次数)中。如果用户设置了Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作。
步骤3:将分区数据的元信息写到内存索引数据结构SpillRecord中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存索引大小超过1MB,则将内存索引写到文件output/spillN.out.index中。
(5)Merge阶段:当所有数据处理完成后,MapTask对所有临时文件进行一次合并,以确保最终只会生成一个数据文件。
当所有数据处理完后,MapTask会将所有临时文件合并成一个大文件,并保存到文件output/file.out中,同时生成相应的索引文件output/file.out.index。
在进行文件合并过程中,MapTask以分区为单位进行合并。对于某个分区,它将采用多轮递归合并的方式。每轮合并mapreduce.task.io.sort.factor(默认10)个文件,并将产生的文件重新加入待合并列表中,对文件排序后,重复以上过程,直到最终得到一个大文件。
让每个MapTask最终只生成一个数据文件,可避免同时打开大量文件和同时读取大量小文件产生的随机读取带来的开销。

3.6.2 ReduceTask工作机制

在这里插入图片描述
(1)Copy阶段:ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
(2)Sort阶段:在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。按照MapReduce语义,用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。由于各个MapTask已经实现对自己的处理结果进行了局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可。
(3)Reduce阶段:reduce()函数将计算结果写到HDFS上。

3.6.3 ReduceTask并行度决定机制

回顾:MapTask并行度由切片个数决定,切片个数由输入文件和切片规则决定。
思考:ReduceTask并行度由谁决定?
1)设置ReduceTask并行度(个数)
ReduceTask的并行度同样影响整个Job的执行并发度和执行效率,但与MapTask的并发数由切片数决定不同,ReduceTask数量的决定是可以直接手动设置:
// 默认值是1,手动设置为4
job.setNumReduceTasks(4);
2)实验:测试ReduceTask多少合适
(1)实验环境:1个Master节点,16个Slave节点:CPU:8GHZ,内存: 2G
(2)实验结论:
在这里插入图片描述
(3)注意事项在这里插入图片描述

3.6.4 MapTask & ReduceTask源码解析

1)MapTask源码解析流程

=================== MapTask ===================

context.write(k, NullWritable.get());   //自定义的map方法的写出,进入
output.write(key, value);  
	//MapTask727行,收集方法,进入两次 
collector.collect(key, value,partitioner.getPartition(key, value, partitions));
	HashPartitioner(); //默认分区器
collect()  //MapTask1082行 map端所有的kv全部写出后会走下面的close方法
	close() //MapTask732行
	collector.flush() // 溢出刷写方法,MapTask735行,提前打个断点,进入
sortAndSpill() //溢写排序,MapTask1505行,进入
	sorter.sort()   QuickSort //溢写排序方法,MapTask1625行,进入
mergeParts(); //合并文件,MapTask1527行,进入
	 
collector.close(); //MapTask739行,收集器关闭,即将进入ReduceTask

2)ReduceTask源码解析流程

=================== ReduceTask ===================
if (isMapOrReduce())  //reduceTask324行,提前打断点
initialize()   // reduceTask333行,进入
init(shuffleContext);  // reduceTask375行,走到这需要先给下面的打断点
        totalMaps = job.getNumMapTasks(); // ShuffleSchedulerImpl第120行,提前打断点
         merger = createMergeManager(context); //合并方法,Shuffle第80行
			// MergeManagerImpl第232 235行,提前打断点
			this.inMemoryMerger = createInMemoryMerger(); //内存合并
			this.onDiskMerger = new OnDiskMerger(this); //磁盘合并
rIter = shuffleConsumerPlugin.run();
		eventFetcher.start();  //开始抓取数据,Shuffle第107行,提前打断点
		eventFetcher.shutDown();  //抓取结束,Shuffle第141行,提前打断点
		copyPhase.complete();   //copy阶段完成,Shuffle第151行
		taskStatus.setPhase(TaskStatus.Phase.SORT);  //开始排序阶段,Shuffle第152行
	sortPhase.complete();   //排序阶段完成,即将进入reduce阶段 reduceTask382行
reduce();  //reduce阶段调用的就是我们自定义的reduce方法,会被调用多次
	cleanup(context); //reduce完成之前,会最后调用一次Reducer里面的cleanup方法

3.7 Join应用

1、reducer jion 
	使用BeanUtils工具,将参数封装到临时Bean,通过集合存储临时Bean的数据

2、map jion 适用于两张表中一张极大、一张极小
	将数据放入缓存

3.7.1 Reduce Jion

作用:

bean对象:在bean对象中定义标签

map端:对于不同表/文件的KV对,在map阶段实现打标签,表/文件的连接字段为key(大家都有的字段),其余字段为value,打标签一般是在set中写死对应表名或文件名。

Reducer端:在shuffle阶段hadoop已经帮我们自动按照key对数据进行分组保存。数据流转到Reducer时,Reducer会根据标签对表/文件的数据分开,(根据需求可能还需要对数据进行再处理),最后进行合并

(补充知识点)BeanUtils jar包使用
3.7.2 Map Jion

1)使用场景
Map Join适用于一张表十分小、一张表很大的场景。
2)优点
思考:在Reduce端处理过多的表,非常容易产生数据倾斜。怎么办?
在Map端缓存多张表,提前处理业务逻辑,这样增加Map端业务,减少Reduce端数据的压力,尽可能的减少数据倾斜。
3)具体办法:采用DistributedCache
(1)在Mapper的setup阶段,将文件读取到缓存集合中。
(2)在Driver驱动类中加载缓存。

//缓存普通文件到Task运行节点。
job.addCacheFile(new URI("file:///e:/cache/pd.txt"));
//如果是集群运行,需要设置HDFS路径
job.addCacheFile(new URI("hdfs://hadoop102:8020/cache/pd.txt"));

3.8 数据清洗(ETL)

“ETL,是英文Extract-Transform-Load的缩写,用来描述将数据从来源端经过抽取(Extract)、转换(Transform)、加载(Load)至目的端的过程。ETL一词较常用在数据仓库,但其对象并不限于数据仓库
在运行核心业务MapReduce程序之前,往往要先对数据进行清洗,清理掉不符合用户要求的数据。清理的过程往往只需要运行Mapper程序,不需要运行Reduce程序

3.9 MapReduce开发总结

1)输入数据接口:InputFormat
(1)默认使用的实现类是:TextInputFormat
(2)TextInputFormat的功能逻辑是:一次读一行文本,然后将该行的起始偏移量作为key,行内容作为value返回。
(3)CombineTextInputFormat可以把多个小文件合并成一个切片处理,提高处理效率。
2)逻辑处理接口:Mapper
用户根据业务需求实现其中三个方法:map() setup() cleanup ()
3)Partitioner分区
(1)有默认实现 HashPartitioner,逻辑是根据key的哈希值和numReduces来返回一个分区号;key.hashCode()&Integer.MAXVALUE % numReduces
(2)如果业务上有特别的需求,可以自定义分区。
4)Comparable排序
(1)当我们用自定义的对象作为key来输出时,就必须要实现WritableComparable接口,重写其中的compareTo()方法。
(2)部分排序:对最终输出的每一个文件进行内部排序。
(3)全排序:对所有数据进行排序,通常只有一个Reduce。
(4)二次排序:排序的条件有两个。
5)Combiner合并
Combiner合并可以提高程序执行效率,减少IO传输。但是使用时必须不能影响原有的业务处理结果。
6)逻辑处理接口:Reducer
用户根据业务需求实现其中三个方法:reduce() setup() cleanup ()
7)输出数据接口:OutputFormat
(1)默认实现类是TextOutputFormat,功能逻辑是:将每一个KV对,向目标文本文件输出一行。
(2)用户还可以自定义OutputFormat。

4、MR之Hadoop压缩

4.1 概述

(1)压缩的优缺点
优点:减少磁盘IO,减少磁盘存储空间
缺点:增加CPU开销
思考:MR的哪些位置可以压缩
map阶段—可以解压文件。也可以压缩,但reducer阶段也需解压和压缩
(2)压缩原则
IO密集 多用
运算密集 少用

4.2 五种压缩编码(默认自带)

1)压缩算法对比介绍
在这里插入图片描述
2)压缩性能的比较
在这里插入图片描述
http://google.github.io/snappy/

Snappy is a compression/decompression library. It does not aim for maximum compression, or compatibility with any other compression library; instead, it aims for very high speeds and reasonable compression. For instance, compared to the fastest mode of zlib, Snappy is an order of magnitude faster for most inputs, but the resulting compressed files are anywhere from 20% to 100% bigger.On a single core of a Core i7 processor in 64-bit mode, Snappy compresses at about 250 MB/sec or more and decompresses at about 500 MB/sec or more.

bzip2:压缩比高,可用于冷数据(不会删除但也不常用的数据)
LZ0(拉兹罗):压缩比一般需要安装、可切片,需建索引并指定输入格式
snappy:可直接使用,不能切片(解决不能切片:可以前期数据存储时就是snappy格式,大小128M一个),可以自己再了解

4.3 压缩方式选择(考虑3点)

压缩/解压缩速度
压缩率(压缩后存储大小)
压缩后是否可以支持切片
— 需要知道各压缩方式的优缺点
压缩位置选择:压缩可以在MapReduce作用的任意阶段启用。

总结:压缩可以减少IO,但不一定会让计算变快

5、Yarn

Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等运算程序则相当于运行于操作系统之上的应用程序。

5.1 Yarn基础架构

YARN主要由ResourceManager、NodeManager、ApplicationMaster和Container等组件构成。
在这里插入图片描述
常驻:RM NM
RM 的作用 1234
NM 作用 123
临时:ApplicationMaster container
ApplicationM 由RM直接启动或监控
作用:为应用程序申请资源并分配给内部的任务
container(容器)
任务跑在container里,不同的任务管理自己的

5.2 Yarn工作机制重点

在这里插入图片描述
(1)MR程序提交到客户端所在的节点。
(2)YarnRunner向ResourceManager申请一个Application。
(3)RM将该应用程序的资源路径返回给YarnRunner。
(4)该程序将运行所需资源提交到HDFS上。
(5)程序资源提交完毕后,申请运行mrAppMaster。
(6)RM将用户的请求初始化成一个Task。
(7)其中一个NodeManager领取到Task任务。
(8)该NodeManager创建容器Container,并产生MRAppmaster。
(9)Container从HDFS上拷贝资源到本地。
(10)MRAppmaster向RM 申请运行MapTask资源。
(11)RM将运行MapTask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器。
(12)MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager分别启动MapTask,MapTask对数据分区排序。
(13)MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask。
(14)ReduceTask向MapTask获取相应分区的数据。
(15)程序运行完毕后,MR会向RM申请注销自己。

5.3 作业提交全过程

HDFS、Yarn、MapReduce三者关系
在这里插入图片描述

作业提交过程之Yarn

在这里插入图片描述
作业提交过程之HDFS mapReduce

在这里插入图片描述
作业提交全过程详解
(1)作业提交
第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。
第2步:Client向RM申请一个作业id。
第3步:RM给Client返回该job资源的提交路径和作业id。
第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。
第5步:Client提交完资源后,向RM申请运行MrAppMaster。
(2)作业初始化
第6步:当RM收到Client的请求后,将该job添加到容量调度器中。
第7步:某一个空闲的NM领取到该Job。
第8步:该NM创建Container,并产生MRAppmaster。
第9步:下载Client提交的资源到本地。
(3)任务分配
第10步:MrAppMaster向RM申请运行多个MapTask任务资源。
第11步:RM将运行MapTask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器。
(4)任务运行
第12步:MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager分别启动MapTask,MapTask对数据分区排序。
第13步:MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask。
第14步:ReduceTask向MapTask获取相应分区的数据。
第15步:程序运行完毕后,MR会向RM申请注销自己。
(5)进度和状态更新
YARN中的任务将其进度和状态(包括counter)返回给应用管理器, 客户端每秒(通过mapreduce.client.progressmonitor.pollinterval设置)向应用管理器请求进度更新, 展示给用户。
(6)作业完成
除了向应用管理器请求作业进度外, 客户端每5秒都会通过调用waitForCompletion()来检查作业是否完成。时间间隔可以通过mapreduce.client.completion.pollinterval来设置。作业完成之后, 应用管理器和Container会清理工作状态。作业的信息会被作业历史服务器存储以备之后用户核查。

5.3 yarn调度器和调度算法(重点)

5.3.1调度器(三个)

FIFO、容量(Capacity Scheduler)(hadoop2.x之后都是容量)和公平(Fair Scheduler),后两个以FIFO为基础,公平又建立在容量上
apache 默认调度器 容量; CDH默认调度器 公平
公平/容量默认一个default 队列,需要创建多队列

5.3.2 每个调度器特点

FIFO:单队列,根据提交作业的先后顺序,先来先服务
优点:简单易懂;
缺点:不支持多队列,生产环境很少使用;
容量:
在这里插入图片描述
容量资源分配:
在这里插入图片描述
公平:
在这里插入图片描述
公平调度器–缺额:
在这里插入图片描述
供应调度器队列资源分配方式:
在这里插入图片描述
公平调度器资源分配算法
在这里插入图片描述

相同点:支持多队列,可以借资源,支持多用户
不同点:容量调度器:优先满足先进来的任务执行
公平调度器,在队列里面的任务公平享有队列资源

5.3.3 生产环境怎么选

中小企业,对并发度要求不高,选择容量
中大企业,对并发度要求比较高,选择公平。
1)在生产环境怎么创建队列?
(1)调度器默认就1个default队列,不能满足生产要求。
(2)按照框架:hive /spark/ flink 每个框架的任务放入指定的队列(企业用的不是特别多)
(3)按照业务模块:登录注册、购物车、下单、业务部门1、业务部门2
2)创建多队列的好处?
(1)因为担心员工不小心,写递归死循环代码,把所有资源全部耗尽。
(2)实现任务的降级使用,特殊时期保证重要的任务队列资源充足。11.11 6.18
业务部门1(重要)=》业务部门2(比较重要)=》下单(一般)=》购物车(一般)=》登录注册(次要)

5.3.4 开发需要重点掌握
1)队列运行原理	
2)Yarn常用命令
3)核心参数配置
4)配置容量调度器和公平调度器。
5)tool接口使用。

Hadoop的优化与新特性

重点内容:

资源均衡
黑白名单----服务器的服役和退役
HA高可用

课上笔记:

1、HDFS多目录
2、HDFS集群扩容和退役
	2、1 开启数据均衡命令  这里的参数  10以下基本没效果,命令不会执行
	2、2 白名单添加
	白名单的控制范围比黑名单大,黑名单是在白名单的基础上进行处理的
	2、3 黑名单退役
		用于服务器退役,完成的是退役服务器的数据转移
3、故障排除

4、MR的优化方法
(1)数据输入和Map 阶段
--数据倾斜(重点看下)
	---combiner
减少溢写次数: 环形缓冲区   可以从100M 80% 上调,保证20M以上的保留空间
减少合并次数:
在map之后,在不影响业务逻辑的情况下,尽可能处理combiner
(2)reduce阶段
对应业务设置Map和Reduce数
设置Map、Reduce共存(我们做不了)		
规避使用Reduce
合理设置Reduce端的buffer:在某阈值时进行落盘
(3)IO传输
5、常用的调优参数(了解,最好记忆)
6、Hadoop小文件优化处理
7、新特性
	-- 纠删码(可以多了解,现在用得少)
8、HA高可用
--思考问题
(1)
(2)
(3)


JN 
启动Hdfs-HA 集群
--先启动JN再进行格式化

ZooKeeper

重点内容:


课上笔记:

1、概述
	ZooKeeper是开源的、分布式的
	为分布式应用提供协调服务
	ZooKeeper = 文件系统+通知机制
2、ZooKeeper特点(6点)
	Leader是唯一的
	半数机制:集群中只要有半数以上节点存货,Zookeeper集群就能正常服务
	全局机制:全局数据一致:每个Server保存一份相同的数据副本,保证Client连接到任一副本,数据都一致
	更新请求顺序
	原子性
	实时性
3、数据结构
	既是目录,也是文件,文件大小1M
4、应用场景
5、Zookeeper命令
	--- 临时节点(重点)
选举机制:
	半数:半数成立才回产生leader
	自私: 每个都想做leader
	墙头草: 谁更强,我就选谁
6、Zookeeper  API 
	1、环境准备
		(1)创建客户端对象
		(2)使用客户端对象进行操作
		(3)关闭客户端
		(4)

`

Hadoop的优化与新特性

重点内容:

资源均衡
黑白名单----服务器的服役和退役
HA高可用

课上笔记:

1、HDFS多目录
2、HDFS集群扩容和退役
	2、1 开启数据均衡命令  这里的参数  10以下基本没效果,命令不会执行
	2、2 白名单添加
	白名单的控制范围比黑名单大,黑名单是在白名单的基础上进行处理的
	2、3 黑名单退役
		用于服务器退役,完成的是退役服务器的数据转移
3、故障排除

4、MR的优化方法
(1)数据输入和Map 阶段
--数据倾斜(重点看下)
	---combiner
减少溢写次数: 环形缓冲区   可以从100M 80% 上调,保证20M以上的保留空间
减少合并次数:
在map之后,在不影响业务逻辑的情况下,尽可能处理combiner
(2)reduce阶段
对应业务设置Map和Reduce数
设置Map、Reduce共存(我们做不了)		
规避使用Reduce
合理设置Reduce端的buffer:在某阈值时进行落盘
(3)IO传输
5、常用的调优参数(了解,最好记忆)
6、Hadoop小文件优化处理
7、新特性
	-- 纠删码(可以多了解,现在用得少)
8、HA高可用
--思考问题
(1)
(2)
(3)


JN 
启动Hdfs-HA 集群
--先启动JN再进行格式化

ZooKeeper

重点内容:


课上笔记:

1、概述
	ZooKeeper是开源的、分布式的
	为分布式应用提供协调服务
	ZooKeeper = 文件系统+通知机制
2、ZooKeeper特点(6点)
	Leader是唯一的
	半数机制:集群中只要有半数以上节点存货,Zookeeper集群就能正常服务
	全局机制:全局数据一致:每个Server保存一份相同的数据副本,保证Client连接到任一副本,数据都一致
	更新请求顺序
	原子性
	实时性
3、数据结构
	既是目录,也是文件,文件大小1M
4、应用场景
5、Zookeeper命令
	--- 临时节点(重点)
选举机制:
	半数:半数成立才回产生leader
	自私: 每个都想做leader
	墙头草: 谁更强,我就选谁
6、Zookeeper  API 
	1、环境准备
		(1)创建客户端对象
		(2)使用客户端对象进行操作
		(3)关闭客户端
		(4)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值