一、Yarn原理
Yarn是一个分布式资源管理和调度平台,负责为运算程序提供服务器运算资源。其上可运行各类分布式运算程序。相当于一个分布式的操作系统平台,而MapReduce等运算程序则相当于运行于操作系统之上的应用程序。
1、Yarn基础架构
YARN主要由ResourceManager、NodeManager、ApplicationMaster和Container等组件构成。其中NodeManager中包含ApplicationMaster、container
YARN 也是典型的 Master-Slave 架构,Master 为 ResourceManager(RM), Slave 为 NodeManager(NM)。
RM 负责接收用户提交的任务,并且决定为任务分配多少资源和调度到哪个 NM 去执行;NM 是真正执行任务的节点,周期性的向 RM 汇报自己的资源使用状况并领取 RM 分配的任务,负责启动和停止任务相关的进程等工作。
在master node上运行ResourceManager。
每个datanode上运行一个NodeManager。
并把该dataNode上的所有计算资源(CPU、内存)视为一个/多个Container,而Container可以被分配执行一个task(ApplicationMaster、map task、reduce task等)。
RM主要作用:
-
处理客户端请求
-
启动或者监控AppMaster(告诉AppMaster空闲的NodeManager)
-
监控 NodeManager 资源使用情况和各个Container的运行状态
-
资源的分配及调度
RM包括Scheduler(定时调度器)和ApplicationManager(应用管理器)。
Scheduler是一个资源调度器,它主要负责协调集群中各个应用的资源分配,保障整个集群的运行效率。
Scheduler的角色是一个纯调度器,它只负责调度Containers,不会关心应用程序监控及其运行状态等信息,它不做监控以及应用程序的状态跟踪,并且不保证会重启应用程序本身或者硬件出错而执行失败的应用程序。
ApplicationManager应用程序管理的功能如下:
- 主要负责接收job的提交请求,为应用分配第一个Container来运行ApplicationMaster
- 还有就是负责监控ApplicationMaster,并在遇到失败时重启运行 ApplicationMaster的Container
NodeManager主要作用:
-
管理单个节点上的资源
-
定时向RM汇报本节点上资源使用情况和各个Container的运行状态
-
处理来自RM的命令
-
处理来自AppMaster的命令(Container的启动/停止等)
AppMaster 主要作用:
-
向RM请求资源(用Container表示)
-
与NodeManager通信(启动/停止Container)
-
为应用程序申请资源并分配给内部的任务
-
任务的监控与容错(监控所有任务运行状态,并在任务运行失败时重新为任务申请资源以重启任务)
Container(容器):
对任务的运行环境进行抽象,封装cpu、内存等多维度的资源及环境变量、启动命令 等任务相关信息。Container是Yarn框架的计算单元,是具体执行应用task(如map task、reduce task)的基本单位。一个节点会运行多个Container,但一个Container不会跨节点。
2、Yarn工作机制(MR作业提交过程)
(1)作业提交
第1步:客户端向ResourceManager发送提交job的请求
第2步:提交job后,客户端会通过客户端所在节点的YRANRUNNER向ResourceManager(之后简称rm)申请提交一个application(用户提交的任何一个应用程序,在YARN中被称为Application)。
第3步:Yarn的ResourceManager会返回一个临时工作目录(hdfs://xxx…/staging)和jobid(新版本叫application_id),然后拼接为一个job的资源提交路径 (hdfs://…./staging/jobid)
第4步:客户端在临时工作目录下创建以jobid为名的文件夹,将
- job的切片规划(调用FileInputFormat.getSplits()获取切片规划List)序列化成的文件job.split
- job.xml文件(job的相关参数)
- job的jar包(job.jar)
拷贝到刚才拼接成的资源提交路径
第5步:客户端提交资源后,向ResourceManager申请初始容器,用来运行MrAppMaster
(2)作业初始化
第6步:当ResourceManager收到客户端请求后,将申请容器请求初始化成一个Task,并添加到容量调度器中(队列中),ResourceManager会将任务分配给一个资源比较宽裕的节点
第7步:某一个空闲的NodeManager领取到该Task任务。
第8步:该NodeManager创建容器Container,并产生MRAppmaster。
第9步:MRAppMaster从HDFS(之前的资源目录)上拷贝资源到容器。
(3)任务分配
第10步:MRAPPMaster根据客户端计算好的输入切片,为每一个切片创建一个map任务对象,根据 mapreduce.job.reduces 创建一定数量的reduce任务对象。MRAPPMaster会为作业中所有的map任务以及reduce任务向resourcemanager请求 container(包括数量、所需资源量、所在位置等因素)。为map任务的请求会首先进行并且相对于reduce任务请求有更高的优先级。当map任务完成率达到了5%之后才会为reduce任务发送容器请求。
第11步:RM中的Scheduler(调度器)将运行MapTask任务和Reduce Task任务放在任务队列中,并分配给多个NodeManager,NodeManager分别领取任务并创建容器。
(4)任务运行
第12步:MRAPPMaster与接收到任务的nodemanager通信,启动容器。任务通过一个java app来执行,该app的主入口类是YarnChild。YarnChild会先到MRAPPMaster获取jar包
第13步:MRAppMaster同时启动maptask任务(mrappmaster向yarnchild发送程序启动命令,实际是java -cp xxxx)
第14步: maptask向MRAppMaster汇报自己的任务运行状况和进度
第15步:MRAppMaster启动reducetask
第16步:ReduceTask向MapTask获取相应分区的数据并开始运行。
第17步: reducetask向MRAppMaster汇报自己的任务运行状况和进度
第18步: MRAppMaster将job的整体工作进度汇报给resourceManger
第19步: 当maptask或者reducetask运行完成,MRAPPMaster就会进行资源回收。
第20步:程序运行完毕后,MR会向RM申请注销自己。
回收资源过程:
- 回收对象YarnChild
- 释放Task容器
- 回收MRAppMaster对象
- 回收初始容器
- 清理工作目录(资源目录)
二、Yarn调度器和调度算法
目前,Hadoop作业调度器主要有三种:
- FIFO
- 容量调度器(Capacity Scheduler)
- 公平调度器(Fair Scheduler)。
Apache Hadoop3.1.3默认的资源调度器是Capacity Scheduler。
CDH框架默认调度器是Fair Scheduler。
具体设置详见:yarn-default.xml文件
<property>
<description>The class to use as the resource scheduler.</description>
<name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
</property>
1、先进先出调度器(FIFO)
FIFO调度器(First In First Out):单队列,根据提交作业的先后顺序,先来先服务。
job1后面的任务都会被阻塞
优点:简单易懂;
缺点:不支持多队列,生产环境很少使用;
小结:
- 一个队列可以使用yarn的全部资源;
- 后提交的任务必须等前面的任务运行完成之后,才可以得到资源并执行。
- 先进先出,同一时间队列中只有一个任务在执行
2、容量调度器(Capacity Scheduler)
Capacity Scheduler是Yahoo开发的多用户调度器。
资源分配算法:
(1)分配新的job任务时,首先计算每个队列中正在运行task个数与其队列应该分配的资源量做比值,然后选择比值最小的队列。比如如图队列A15个task,20%资源量,那么就是15/0.2=75,队列B是25/0.5=50 ,队列C是25/0.3=83.33 。所以选择最小值队列B。
(2)其次,按照job任务的优先级和时间顺序,同时要考虑到用户的资源量和内存的限制,对队列中的job任务进行排序执行。
(3)多个队列同时按照任务队列内的先后顺序一次执行。例如下图中job11、job21、job31分别在各自队列中顺序比较靠前,三个任务就同时执行。
3、公平调度器(Fair Scheduler)
Fair Schedulere是Facebook开发的多用户调度器。
三、Yarn常用命令
1、 yarn application查看任务
(1)列出所有Application:yarn application -list
(2)根据Application状态过滤:yarn application -list -appStates <状态>(所有状态:ALL、NEW、NEW_SAVING、SUBMITTED、ACCEPTED、RUNNING、FINISHED、FAILED、KILLED)
例: yarn application -list -appStates FINISHED
(3)Kill掉Application:yarn application -kill <ApplicationId>
2、yarn logs查看日志
(1)查询Application日志:yarn logs -applicationId <ApplicationId>
(2)查询Container日志:yarn logs -applicationId <ApplicationId> -containerId <ContainerId>
3、 yarn applicationattempt查看尝试运行的任务
(1)列出所有Application尝试的列表:yarn applicationattempt -list <ApplicationId>
(2)打印ApplicationAttemp状态:yarn applicationattempt -status <ApplicationAttemptId>
4、 yarn container查看容器
(1)列出所有Container:yarn container -list <ApplicationAttemptId>
(2)打印Container状态: yarn container -status <ContainerId>
5、yarn node查看节点状态
列出所有节点:yarn node -list -all
6、yarn rmadmin更新配置
加载队列配置:yarn rmadmin -refreshQueues
注意:只能动态刷新与队列相关的配置,不能刷新与yarn相关的配置
7、yarn queue查看队列
打印队列信息:yarn queue -status <QueueName>
四、Yarn生产环境核心参数
1、etc/hadoop/目录下yarn-site.xml文件配置
<configuration>
<!-- resource,manager主节点所在机器 -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>linux1</value>
</property>
<!-- 为mr程序提供shuffle服务 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!-- 一台NodeManager的总可用内存资源 -->
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>4096</value>
</property>
<!-- 一台NodeManager的总可用(逻辑)cpu核数 -->
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>4</value>
</property>
<!-- 是否检查容器的虚拟内存使用超标情况 -->
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
<!-- 容器的虚拟内存使用上限:与物理内存的比率 -->
<property>
<name>yarn.nodemanager.vmem-pmem-ratio</name>
<value>2.1</value>
</property>
</configuration>
2、启动脚本中添加
在start-yarn.sh 、stop-yarn.sh中添加
#!/usr/bin/env bash
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root
3、配置从节点(NodeManager)的主机名到workers文件中
linux1
linux2
linux3
启动yarn后在 http://linux1:8088 上提供web页面
五、启动Yarn
start-yarn.sh 启动yarn集群
stop-yarn.sh 停止yarn集群
六、在Yarn上运行MapReduce
1、配置mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=/opt/apps/hadoop-3.1.1</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=/opt/apps/hadoop-3.1.1</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=/opt/apps/hadoop-3.1.1</value>
</property>
</configuration>
HADOOP_MAPRED_HOME应为自己虚拟机上安装hadoop的路径
2、在idea上提交MapReduce
public static void main(String[] args)
throws IOException, ClassNotFoundException, InterruptedException {
//设置job提交的HADOOP_USER_NAME
System.setProperty("HADOOP_USER_NAME","root");
//获取配置文件对象
Configuration conf = new Configuration();
//设置默认文件系统为hdfs
conf.set("fs.defaultFS", "hdfs://linux1:8020");
//设置运行模式为yarn
conf.set("mapreduce.framework.name","yarn");
//设置yarn的主节点位置
conf.set("yarn.resourcemanager.hostname","linux1");
//设置跨平台参数
conf.set("mapreduce.app-submission.cross-platform","true");
//获取job对象
Job job = Job.getInstance(conf);
//关联本Driver程序的jar
job.setJar("D:\\work\\newCode\\HadoopTest\\doit-hadoop\\target\\doit-hadoop-1.0-SNAPSHOT.jar");
//关联mapper和reducer的jar
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//设置mapper的输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//设置最终输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//设置输入路径和输出路径
FileInputFormat.setInputPaths(job, new Path("/wc/input"));
FileOutputFormat.setOutputPath(job, new Path("/wc/output"));
//提交job
boolean b = job.waitForCompletion(true);
System.exit(b ? 0 : 1);
}
- 将 mapred-site.xml 放到 resources 下
- 设置job提交的HADOOP_USER_NAME为root,否则其他用户没有操作HDFS数据的权限
- 若不设置操作的文件系统为HDFS,则会默认操作windows系统
- 需要将项目打包,并用job.setJar(“jar包路径”)关联jar包
3、在linux上提交MapReduce
public static void main(String[] args)
throws IOException, ClassNotFoundException, InterruptedException {
//获取配置文件对象
Configuration conf = new Configuration();
//获取job对象
Job job = Job.getInstance(conf);
job.setJarByClass(WordCountDriver.class);
//关联mapper和reducer的jar
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//设置mapper的输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//设置最终输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//设置输入路径和输出路径
FileInputFormat.setInputPaths(job, new Path("/wc/input"));
FileOutputFormat.setOutputPath(job, new Path("/wc/output"));
//提交job
boolean b = job.waitForCompletion(true);
System.exit(b ? 0 : 1);
}
- 只需在原来的基础上加上job.setJarByClass(Driver类.class);
- 在linux的etc/hadoop/下配置mapred-site.xml
- 将项目打包并将jar包上传到HDFS上
- hadoop jar jar包名 Driver类全包名
为什么用hadoop jar命令:hadoop jar命令会提供Driver类运行所需要的依赖,并且它会去读一些默认的配置文件,提供我们自己的jar包运行所需要的环境