理解分布式计算分而治之的思想
学会提交MapReduce程序
掌握MapReduce执行流程
掌握YARN功能与架构组件
掌握程序提交YARN交互流程
理解YARN调度策略
掌握Hadoop HA实现原理
#1、初识MapReduce
MapReduce背后的思想 先分再合,分而治之
MapReduce设计构思
官方MapReduce示例
MapReduce Python接口
#2、MapReduce基本原理
整体流程梳理
map阶段执行流程
reduce阶段执行流程
shuffle机制
#3、Hadoop YARN
介绍:集群资源管理 任务调度
3大组件 架构
程序在yarn运行流程:以mr程序提交为例
yarn调度器
#4、Hadoop HA集群
高可用概念:持续可用 一直可用
解决单点故障问题 主备集群
Hadoop HDFS HA实现方案--QJM、YARN HA
搭建HA集群
使用场景:面对复杂的任务、庞大的任务如何高效处理?
步骤
分的阶段(局部并行计算)–map
把复杂的任务拆分成若干个小的任务。
拆分的目的以并行方式处理小任务提高效率。
#前提:任务可以拆分,拆分之后没有依赖关系。
结果:每个任务处理完都是一个局部的结果。
map侧重于映射(对应关系) 任务1-->结果1 任务2-->结果2
汇总阶段(全局汇总计算)–reduce
把上一个分的阶段局部结果进行全局汇总 得到最终结果。
reduce指的是结果数量的减少 汇总。
如何面对大数据场景
#使用MapReduce思路来处理大数据。
先把数据集拆分若干个小的数据集,前提是可以拆分并且拆分之后没有依赖。
拆分之后可以并行计算提高计算。
再通过全局汇总计算得出最终结果。
构建了函数式编程模型Map Reduce
#函数本质就是映射。
f(x)=2x+1
当x=1 f(1)=3
当x=2 f(2)=5
x-->f(x) 一一对应的映射关系。
#对应MapReduce来说 每个阶段都是输入数据经过处理对应着输出。
MapReduce处理的数据类型是<key,value>键值对。
实际使用中 考虑每个阶段输入输出 key value是什么。
统一构架,隐藏系统层细节
精准的把技术问题和业务问题区分。 技术是通用的 业务不通用的。
hadoop实现了底层所有的技术问题。 --->90%代码 怎么做(how to do)
用户实现业务问题 --->10%代码 做什么(what need to do)
使用简单不代表技术简单 只能说MapReduce底层封装太漂亮。
最终MR程序需要用户的代码和Hadoop自己实现的代码整合在一起 才能叫做完整MR程序。
由于当下企业中MapReduce计算引擎已经日薄西山,所以很少涉及到MapReduce编程了。
可以通过官方提供的示例来感受MapReduce。
提交程序
[root@node1 mapreduce]# pwd
/export/server/hadoop-3.3.0/share/hadoop/mapreduce
[root@node1 mapreduce]# hadoop jar hadoop-mapreduce-examples-3.3.0.jar pi 10 50
#第一个参数:pi表示MapReduce程序执行圆周率计算任务;
#第二个参数:用于指定map阶段运行的任务task次数,并发度,这里是10;
#第三个参数:用于指定每个map任务取样的个数,这里是50。
执行过程日志观察与梳理
#mr程序的执行需要硬件资源(cpu ram) 而yarn正好管理这些资源 所以第一步首先连接yarn申请资源
#mr程序分为两步
- map阶段
- reduce阶段
#每个阶段都会运行task任务
map阶段的任务叫做maptask
reduce阶段的任务叫做reducetask.
背景
网页倒排索引 统计关键字在页面中出现的次数。
业务需求
统计文件中每个单词出现的总次数。
#map阶段的核心:把输入的数据经过切割,全部标记1,因此输出就是<单词,1>。
#shuffle阶段核心:经过默认的排序分区分组,key相同的单词会作为一组数据构成新的kv对。
#reduce阶段核心:处理shuffle完的一组数据,该组数据就是该单词所有的键值对。对所有的1进行累加求和,就是单词的总次数。
#读取数据组件 写出数据组件MR框架已经封装好(自带)
#上传课程资料中的文本文件1.txt到HDFS文件系统的/input目录下,如果没有这个目录,使用shell创建
hadoop fs -mkdir /input
hadoop fs -put 1.txt /input
#准备好之后,执行官方MapReduce实例,对上述文件进行单词次数统计
第一个参数:wordcount表示执行单词统计任务;
第二个参数:指定输入文件的路径;
第三个参数:指定输出结果的路径(该路径不能已存在)
[root@node1 mapreduce]# pwd
/export/server/hadoop-3.3.0/share/hadoop/mapreduce
[root@node1 mapreduce]# hadoop jar hadoop-mapreduce-examples-3.3.0.jar wordcount /input /output
mapper
public class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//每一次读取到一行内容
String line = value.toString();
//根据分隔符进行切割
String[] words = line.split("\\s+");
//遍历单词数组
for (String word : words) {
//输出数据 把每个单词标记1 <单词,1>
//使用框架提供的上下文对象 进行数据的输出
context.write(new Text(word),new IntWritable(1));
}
}
}
reducer
public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
/**
* Q: 当所有的数据来到reducer之后 内部有什么行为?
*
1、所有的数据排序 排序规则:key的字典序 a-z
*
*
2、分组grouping 分组规则:key相同的分为一组
*
*
3、每组构成一个新的kv对 去调用reduce方法
* 新key: 该组共同的key
* 新value: 该组所有的value组成的一个迭代器Iterable(理解为类似于集合数据结构)
* ---->
* --->
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//定义个统计变量
int count = 0;
//遍历迭代器
for (IntWritable value : values) {
//累加
count += value.get();
}
//使用上下文输出结果
context.write(key,new IntWritable(count));
}
}
#虽然Hadoop是用Java编写的一个框架, 但是并不意味着他只能使用Java语言来操作;
#在Hadoop-0.14.1版本后, Hadoop支持了Python和C++语言;
#在Python中的sys包中存在stdin和stdout(输入输出流), 可以利用这个方式来进行MapReduce的编写;
#在Hadoop的文档中提到了Hadoop Streaming, 可以使用流的方式来操作它;
https://hadoop.apache.org/docs/r3.3.0/hadoop-streaming/HadoopStreaming.html
mapper.py
import sys
for line in sys.stdin:
# 捕获输入流
line = line.strip()
# 根据分隔符切割单词
words = line.split()
# 遍历单词列表 每个标记1
for word in words:
print("%s\t%s" % (word, 1))
reducer.py
import sys
# 保存单词次数的字典 key:单词 value:总次数
word_dict = {}
for line in sys.stdin:
line = line.strip()
word, count = line.split('\t')
# count类型转换
try:
count = int(count)
except ValueError:
continue
# 如果单词位于字典中 +1,如果不存在 保存并设初始值1
if word in word_dict:
word_dict[word] += 1
else:
word_dict.setdefault(word, 1)
# 结果遍历输出
for k, v in word_dict.items():
print('%s\t%s' % (k, v))
Python3在Linux安装
#1、安装编译相关工具
yum -y groupinstall "Development tools"
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
yum install libffi-devel -y
#2、解压Python安装包
tar -zxvf Python-3.8.5.tgz
#3、编译、安装Python
mkdir /usr/local/python3 #创建编译安装目录
cd Python-3.8.5
./configure --prefix=/usr/local/python3
make && make install #make编译c源码 make install 编译后的安装
#安装过,出现下面两行就成功了
Installing collected packages: setuptools, pip
Successfully installed pip-20.1.1 setuptools-47.1.0
#4、创建软连接
# 查看当前python软连接
[root@node2 Python-3.8.5]# ll /usr/bin/ |grep python
-rwxr-xr-x. 1 root root 11232 Aug 13 2019 abrt-action-analyze-python
lrwxrwxrwx. 1 root root 7 May 17 11:36 python -> python2
lrwxrwxrwx. 1 root root 9 May 17 11:36 python2 -> python2.7
-rwxr-xr-x. 1 root root 7216 Aug 7 2019 python2.7
#默认系统安装的是python2.7 删除python软连接
rm -rf /usr/bin/python
#配置软连接为python3
ln -s /usr/local/python3/bin/python3 /usr/bin/python
#这个时候看下python默认版本
python -V
#删除默认pip软连接,并添加pip3新的软连接
rm -rf /usr/bin/pip
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip
#5、更改yum配置
#因为yum要用到python2才能执行,否则会导致yum不能正常使用(不管安装 python3的那个版本,都必须要做的)
vi /usr/bin/yum
把 #! /usr/bin/python 修改为 #! /usr/bin/python2
vi /usr/libexec/urlgrabber-ext-down
把 #! /usr/bin/python 修改为 #! /usr/bin/python2
vi /usr/bin/yum-config-manager
#!/usr/bin/python 改为 #!/usr/bin/python2
代码的本地测试
#上传待处理文件 和Python脚本到Linux上
[root@node2 ~]# pwd
/root
[root@node2 ~]# ll
-rw-r--r-- 1 root root 105 May 18 15:12 1.txt
-rwxr--r-- 1 root root 340 Jul 21 16:16 mapper.py
-rwxr--r-- 1 root root 647 Jul 21 16:18 reducer.py
#使用shell管道符运行脚本测试
[root@node2 ~]# cat 1.txt | python mapper.py |sort|python reducer.py
allen 4
apple 3
hadoop 1
hello 5
mac 1
spark 2
tom 2
代码提交集群执行
#上传处理的文件到hdfs
#上传Python脚本到linux
#提交程序执行
hadoop jar /export/server/hadoop-3.3.0/share/hadoop/tools/lib/hadoop-streaming-3.3.0.jar \
-D mapred.reduce.tasks=1 \
-mapper "python mapper.py" \
-reducer "python reducer.py" \
-file mapper.py -file reducer.py \
-input /input/* \
-output /outpy
数据都是以
关于inputpath
关于outputpath
FileAlreadyExistsException: Output directory file:/D:/datasets/wordcount/output already exists
文件的个数
文件的大小
split size=block size 切片的大小受数据块的大小控制
当reducetask>=2,数据就会分区了。
map阶段处理的数据如何传递给reduce阶段,是MapReduce框架中最关键的一个流程,这个流程就叫shuffle。
shuffle: 洗牌、发牌——(核心机制:数据分区,排序,合并)
shuffle是Mapreduce的核心,它分布在Mapreduce的map阶段和reduce阶段。一般把从Map产生输出开始到Reduce取得数据作为输入之前的过程称作shuffle。
(1)Collect阶段:将MapTask的结果输出到默认大小为100M的环形缓冲区,保存的是key/value,Partition分区信息等。
(2)Spill阶段:当内存中的数据量达到一定的阀值的时候,就会将数据写入本地磁盘,在将数据写入磁盘之前需要对数据进行一次排序的操作,如果配置了combiner,还会将有相同分区号和key的数据进行排序。
(3)Merge阶段:把所有溢出的临时文件进行一次合并操作,以确保一个MapTask最终只产生一个中间数据文件。
(4)Copy阶段: ReduceTask启动Fetcher线程到已经完成MapTask的节点上复制一份属于自己的数据,这些数据默认会保存在内存的缓冲区中,当内存的缓冲区达到一定的阀值的时候,就会将数据写到磁盘之上。
(5)Merge阶段:在ReduceTask远程复制数据的同时,会在后台开启两个线程对内存到本地的数据文件进行合并操作。
(6)Sort阶段:在对数据进行合并的同时,会进行排序操作,由于MapTask阶段已经对数据进行了局部的排序,ReduceTask只需保证Copy的数据的最终整体有效性即可。
Shuffle中的缓冲区大小会影响到mapreduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快
yarn是一个通用资源管理系统和调度平台。
资源指的跟程序运行相关的硬件资源 比如:CPU RAM
Apache Hadoop YARN (Yet Another Resource Negotiator,另一种资源协调者)是一种新的 Hadoop 资源管理器,它是一个通用资源管理系统和调度平台,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来了巨大好处。
可以把yarn理解为相当于一个分布式的操作系统平台,而mapreduce等运算程序则相当于运行于操作系统之上的应用程序,Yarn为这些程序提供运算所需的资源(内存、cpu)。
YARN是一个资源管理、任务调度的框架,主要包含三大模块:ResourceManager(RM)、NodeManager(NM)、ApplicationMaster(AM)。
ResourceManager负责所有资源的监控、分配和管理;
ApplicationMaster负责每一个具体应用程序的调度和协调;
NodeManager负责每一个节点的维护。
对于所有的applications,RM拥有绝对的控制权和对资源的分配权。而每个AM则会和RM协商资源,同时和NodeManager通信来执行和监控task
(1)client向RM提交应用程序,其中包括启动该应用的ApplicationMaster的必须信息,例如ApplicationMaster程序、启动ApplicationMaster的命令、用户程序等。
(2)ResourceManager启动一个container用于运行ApplicationMaster。
(3)启动中的ApplicationMaster向ResourceManager注册自己,启动成功后与RM保持心跳。
(4)ApplicationMaster向ResourceManager发送请求,申请相应数目的container。
(5)ResourceManager返回ApplicationMaster的申请的containers信息。申请成功的container,由ApplicationMaster进行初始化。container的启动信息初始化后,AM与对应的NodeManager通信,要求NM启动container。AM与NM保持心跳,从而对NM上运行的任务进行监控和管理。
(6)container运行期间,ApplicationMaster对container进行监控。container通过RPC协议向对应的AM汇报自己的进度和状态等信息。
(7)应用运行期间,client直接与AM通信获取应用的状态、进度更新等信息。
(8)应用运行结束后,ApplicationMaster向ResourceManager注销自己,并允许属于它的container被收回
理想情况下,我们应用对Yarn资源的请求应该立刻得到满足,但现实情况资源往往是有限的,特别是在一个很繁忙的集群,一个应用资源的请求经常需要等待一段时间才能的到相应的资源。在Yarn中,负责给应用分配资源的就是Scheduler。其实调度本身就是一个难题,很难找到一个完美的策略可以解决所有的应用场景。为此,Yarn提供了多种调度器和可配置的策略供我们选择。
在Yarn中有三种调度器可以选择:FIFO Scheduler ,Capacity Scheduler,Fair Scheduler
FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推
FIFO Scheduler是最简单也是最容易理解的调度器,也不需要任何配置,但它并不适用于共享集群。大的应用可能会占用所有集群资源,这就导致其它应用被阻塞。在共享集群中,更适合采用Capacity Scheduler或Fair Scheduler,这两个调度器都允许大任务和小任务在提交的同时获得一定的系统资源
Capacity 调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。除此之外,队列内部又可以垂直划分,这样一个组织内部的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略
容量调度器 Capacity Scheduler 最初是由 Yahoo 最初开发设计使得 Hadoop 应用能够被多用户使用,且最大化整个集群资源的吞吐量,现被 IBM BigInsights 和 Hortonworks HDP 所采用。
Capacity Scheduler 被设计为允许应用程序在一个可预见的和简单的方式共享集群资源,即"作业队列"。Capacity Scheduler 是根据租户的需要和要求把现有的资源分配给运行的应用程序。Capacity Scheduler 同时允许应用程序访问还没有被使用的资源,以确保队列之间共享其它队列被允许的使用资源。管理员可以控制每个队列的容量,Capacity Scheduler 负责把作业提交到队列中
在Fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。如下图所示,当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
需要注意的是,在下图Fair调度器中,从第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。最终效果就是Fair调度器即得到了高的资源利用率又能保证小任务及时完成
公平调度器 Fair Scheduler 最初是由 Facebook 开发设计使得 Hadoop 应用能够被多用户公平地共享整个集群资源,现被 Cloudera CDH 所采用。
Fair Scheduler 不需要保留集群的资源,因为它会动态在所有正在运行的作业之间平衡资源
HA(High Available), 高可用,是保证业务连续性的有效解决方案,一般有两个或两个以上的节点,分为活动节点(Active)及备用节点(Standby)。通常把正在执行业务的称为活动节点,而作为活动节点的一个备份的则称为备用节点。当活动节点出现问题,导致正在运行的业务(任务)不能正常运行时,备用节点此时就会侦测到,并立即接续活动节点来执行业务。从而实现业务的不中断或短暂中断。
Hadoop1.X版本,NN是HDFS集群的单点故障点,每一个集群只有一个NN,如果这个机器或进程不可用,整个集群就无法使用。为了解决这个问题,出现了一堆针对HDFS HA的解决方案(如:Linux HA, VMware FT, shared NAS+NFS, BookKeeper, QJM/Quorum Journal Manager, BackupNode等)。
在HA具体实现方法不同情况下,HA框架的流程是一致的, 不一致的就是如何存储、管理、同步edits编辑日志文件。
在Active NN和Standby NN之间要有个共享的存储日志的地方,Active NN把edit Log写到这个共享的存储日志的地方,Standby NN去读取日志然后执行,这样Active和Standby NN内存中的HDFS元数据保持着同步。一旦发生主从切换Standby NN可以尽快接管Active NN的工作
hadoop2.x之后,Clouera提出了QJM/Qurom Journal Manager,这是一个基于Paxos算法(分布式一致性算法)实现的HDFS HA方案,它给出了一种较好的解决思路和方案,QJM主要优势如下:
不需要配置额外的高共享存储,降低了复杂度和维护成本。
消除spof(单点故障)。
系统鲁棒性(Robust)的程度可配置、可扩展
基本原理就是用2N+1台 JournalNode 存储EditLog,每次写数据操作有>=N+1返回成功时即认为该次写成功,数据不会丢失了。当然这个算法所能容忍的是最多有N台机器挂掉,如果多于N台挂掉,这个算法就失效了。这个原理是基于Paxos算法。
在HA架构里面SecondaryNameNode已经不存在了,为了保持standby NN时时的与Active NN的元数据保持一致,他们之间交互通过JournalNode进行操作同步。
任何修改操作在 Active NN上执行时,JournalNode进程同时也会记录修改log到至少半数以上的JN中,这时 Standby NN 监测到JN 里面的同步log发生变化了会读取 JN 里面的修改log,然后同步到自己的目录镜像树里面,如下图:
当发生故障时,Active的 NN 挂掉后,Standby NN 会在它成为Active NN 前,读取所有的JN里面的修改日志,这样就能高可靠的保证与挂掉的NN的目录镜像树一致,然后无缝的接替它的职责,维护来自客户端请求,从而达到一个高可用的目的。
在HA模式下,datanode需要确保同一时间有且只有一个NN能命令DN。为此:
每个NN改变状态的时候,向DN发送自己的状态和一个序列号。
DN在运行过程中维护此序列号,当failover时,新的NN在返回DN心跳时会返回自己的active状态和一个更大的序列号。DN接收到这个返回则认为该NN为新的active。
如果这时原来的active NN恢复,返回给DN的心跳信息包含active状态和原来的序列号,这时DN就会拒绝这个NN的命令
HA模式下,会将FailoverController部署在每个NameNode的节点上,作为一个单独的进程用来监视NN的健康状态。FailoverController主要包括三个组件:
(1)HealthMonitor: 监控NameNode是否处于unavailable或unhealthy状态。当前通过RPC调用NN相应的方法完成。
(2)ActiveStandbyElector: 监控NN在ZK中的状态。
(3)ZKFailoverController: 订阅HealthMonitor 和ActiveStandbyElector 的事件,并管理NN的状态,另外zkfc还负责解决fencing(也就是脑裂问题)。
上述三个组件都在跑在一个JVM中,这个JVM与NN的JVM在同一个机器上。但是两个独立的进程。一个典型的HA集群,有两个NN组成,每个NN都有自己的ZKFC进程
ZKFailoverController主要职责:
(1)健康监测:周期性的向它监控的NN发送健康探测命令,从而来确定某个NameNode是否处于健康状态,如果机器宕机,心跳失败,那么zkfc就会标记它处于一个不健康的状态
(2)会话管理:如果NN是健康的,zkfc就会在zookeeper中保持一个打开的会话,如果NameNode同时还是Active状态的,那么zkfc还会在Zookeeper中占有一个类型为短暂类型的znode,当这个NN挂掉时,这个znode将会被删除,然后备用的NN将会得到这把锁,升级为主NN,同时标记状态为Active
(3)当宕机的NN新启动时,它会再次注册zookeper,发现已经有znode锁了,便会自动变为Standby状态,如此往复循环,保证高可靠,需要注意,目前仅仅支持最多配置2个NN
(4)master选举:通过在zookeeper中维持一个短暂类型的znode,来实现抢占式的锁机制,从而判断那个NameNode为Active状态
Yarn作为资源管理系统,是上层计算框架(如MapReduce,Spark)的基础。在Hadoop 2.4.0版本之前,Yarn存在单点故障(即ResourceManager存在单点故障),一旦发生故障,恢复时间较长,且会导致正在运行的Application丢失,影响范围较大。从Hadoop 2.4.0版本开始,Yarn实现了ResourceManager HA,在发生故障时自动failover,大大提高了服务的可靠性。
ResourceManager(简写为RM)作为Yarn系统中的主控节点,负责整个系统的资源管理和调度,内部维护了各个应用程序的ApplictionMaster信息、NodeManager(简写为NM)信息、资源使用等。由于资源使用情况和NodeManager信息都可以通过NodeManager的心跳机制重新构建出来,因此只需要对ApplicationMaster相关的信息进行持久化存储即可。
在一个典型的HA集群中,两台独立的机器被配置成ResourceManger。在任意时间,有且只允许一个活动的ResourceManger,另外一个备用。切换分为两种方式:
手动切换:在自动恢复不可用时,管理员可用手动切换状态,或是从Active到Standby,或是从Standby到Active。
自动切换:基于Zookeeper,但是区别于HDFS的HA,2个节点间无需配置额外的ZFKC守护进程来同步数据