Hadoop-Yarn

57 阅读9分钟

yarn资源调度器

Yarn基础架构

  • YARN主要由Resourcemanager、Nodemanager、ApplicationMaster和Contatiner等组件构成。

作业提交全过(面试题)

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

yarn调度器和调度算法

  • 目前,Hadoop作业调度器主要有三种,FIFO、容量(Capacity Scheduler)和公平(Fair Scheduler)。Apache Hadoop3.1.3默认的调度器是Capacity Scheduler。
  • CDH框架(Cloudra's Distribution Apache Of Hadoop)默认的调度器是Fair Scheduler
  • 具体设置详见:yarn-default文件
<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>

先进先出调度器(FIFO)

  • FIFO调度器(First In First Out): 单队列,根据提交作业的先后顺序,先来先服务。
  • 优点: 简单易懂
  • 缺点: 不支持多队列,生产环境很少使用

容量调度器(Capacity Scheduler)

  • Capacity Scheduler是Yahoo开发的多用户调度器
  • 特点
  • 多队列: 每个队列配置一定的资源,每个队列采用FIFO调度策略。
  • 容量保证:管理员可为每个队列设置资源最低保证和资源使用上限。
  • 灵活性:如果一个队列资源有剩余,可暂时共享给那些需要资源的队列,而一旦队列有了新的应用程序提交,则其他队列借调的资源会归还给该队列。
  • 多租户:(1)支持多用户共享集群和多应用程序同时运行。(2)为了防止同一个用户的作业独占队列中的资源,该调度器会对同一用户提交的作业所占资源进行限制。
  • 容量调度器资源分配算法
  • 队列资源分配:从root开始,使用深度优先搜索算法,优先选择资源占用率低的队列进行分配资源。
  • 作业资源分配:默认按照提交作业的优先级提交时间顺序分配资源。
  • 容器资源分配:按照容器的优先级进行分配资源,如果优先级相同,按照数据本地性原则。(1)任务和数据在同一个节点(2)任务和数据在同一个机架(3)任务和数据不在同一个节点也不在同一个机架。

公平调度器

  • Fair Schedulere是FaceBook开发的多用户调度器
  • 同对垒所用任务共享资源,在时间尺度上获得公平的资源
  • 与容量调度器相同的特点
  • 多队列
  • 容量保证
  • 灵活性
  • 多租户
  • 与容量调度器不同的特点
  • 核心调度策略不同: (1) 容量调度: 优先选择资源利用率低的队列。 (2) 公平调度: 优先选择对资源缺额比例大的
  • 每个队列可以单独设置资源分配方式: (1) 容量调度: FIFO、DRF (2) 公平调度: FIFO、FAIR、DRF
  • 缺额
  • 某一时刻一个作业应获得的资源和实际获取的资源差距叫“缺额”
  • 调度器会优先为缺额大的作业分配资源
  • Fair策略
    • 资源分配步骤:选择队列,选择作业,选择容器
      1. 分别计算比对象的(实际最小资源份额,是否饥饿,资源分配比,资源使用权重比)
      1. 判断两种比较对象的饥饿状态
      1. 其中一个饥饿:饥饿优先
      1. 都饥饿:资源分配比小者优先,若相同,则按照提交时间顺序
      1. 都不饥饿:资源使用权重比小者优先,若相同,则按照提交时间顺序
    • 实际最小份额: mindShare = Min(资源需求量,配置的最小资源)
    • 是否饥饿:isNeedy = 资源使用量 < mindShare(实际最小资源份额)
    • 资源分配比:minShareRatio = 资源使用量 / Max(mindShare, 1)
    • 资源使用权重比:useToWeightRatio = 资源使用量 / 权重

Yarn常用命令

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 application_1691032363493_0002

Yarn logs查看日志

# 1. 查询Application日志
yarn logs -applicationId <ApplicationId>

# 2. 查询Container日志
yarn logs -applicationId <ApplicationId> -containerId <ContainerId>

Yarn applicationattempt 查看尝试运行的任务

# 1.列出Application尝试的列表
yarn applicationattempt -list <applicationId>

# 2. 打印ApplicationAttemp状态
yarn applicationattempt -status <ApplicationAttemptId>

Yarn container查看容器

# 1. 列出所有容器
yarn container -list <ApplicationAttemptId>

# 打印Container状态
yarn container -states <ContainerId>
# 只有在任务跑的途中才能看到container的状态

Yarn node查看阶段状态

# 列出所有节点
yarn node -list -all

Yarn rmadmin更新配置

# 加载队列配置,重读配置文件
yarn rmadmin -refreshQueues

Yarn queue查看队列

# 打印队列信息
yarn queue -status <QueueName>

# 例
yarn queue -status default

Yarn生产环境核心参数配置

ResourceManager相关

# 配置调度器,默认容量调度器,大厂并发度较高,用容量,中小厂并发度小,用公平
yarn.resouecemanager.scheuler.class

# ResourceManager处理调度器请求的线程数量,**默认50**
yarn.resourcemanager.scheduler.client.thread-count

NodeManager相关

# 是否让yarn自己检测硬件进行配置,**默认false**
yarn.nodemanager.resource.detect-hardware-capabilities

# 是否将虚拟核数当做cpu核数, 默认false
yarn.nodemanager.resource.count-logical-processor-as-core

# 虚拟核数和物理核数乘数,如四核八线程,该参数就位2, **默认1.0**
yarn.nodemanager.resource.pcores-vcores-multiplier

# NodeManager使用内存, 默认8G
yarn.nodemanager.resource.memory-mb

# 为系统保留多少内存, 与以上参数,这两个配置一个就行
yarn.nodemanager.resource.system-reserved-memory-mb

# NodeManager使用CPU核数,默认8个, 超过单机核数会崩溃
yarn.nodemanager.resource.cpu-vcores

# 是否开启物理内存检查限制container,默认打开, 使用内存超过实际内存会预警
yarn.nodemanager.vmem-check-enabled

# 虚拟内存物理内存比例,默认2.1
yarn.nodemanager.vmem-pmem-ratio

Container相关

# 容器最小内存, 默认1G
yarn.scheduler.minimum-allocation-mb

# 容器最大内存,默认8G, 超过Nodemanage的使用内存会崩溃
yarn.scheduler.maximum-allocation-mb

# 容器最小cpu核数, 默认1个
yarn.scheduler.minimum-allocation-vcores

# 容器最大CPU核数,默认4个
yarn.scheduler.maximum-allocation-csores

配置多队列的容量调度器

  • 在capacity-scheduler.xml文件中配置如下
<!-- 指定多队列,增加hive队列 -->
<property>
    <name>yarn.scheduler.capacity.root.queues</name>
    <value>default,hive</value>
    <description>
      The queues at the this level (root is the root queue).
    </description>
</property>

<!-- 降低default队列资源额定容量为40%,默认100% -->
<property>
    <name>yarn.scheduler.capacity.root.default.capacity</name>
    <value>40</value>
</property>
 
<!-- 降低default队列资源最大容量为60%,默认100% -->
<property>
    <name>yarn.scheduler.capacity.root.default.maximum-capacity</name>
    <value>60</value>
</property>

<!-- 指定hive队列的资源额定容量 -->
<property>
    <name>yarn.scheduler.capacity.root.hive.capacity</name>
    <value>60</value>
</property>

<!-- 用户最多可以使用队列多少资源,1表示 -->
<property>
    <name>yarn.scheduler.capacity.root.hive.user-limit-factor</name>
    <value>1</value>
</property>

<!-- 指定hive队列的资源最大容量 -->
<property>
    <name>yarn.scheduler.capacity.root.hive.maximum-capacity</name>
    <value>80</value>
</property>

<!-- 启动hive队列 -->
<property>
    <name>yarn.scheduler.capacity.root.hive.state</name>
    <value>RUNNING</value>
</property>

<!-- 哪些用户有权向队列提交作业 -->
<property>
    <name>yarn.scheduler.capacity.root.hive.acl_submit_applications</name>
    <value>*</value>
</property>
 
<!-- 哪些用户有权操作队列,管理员权限(查看/杀死) -->
<property>
    <name>yarn.scheduler.capacity.root.hive.acl_administer_queue</name>
    <value>*</value>
</property>

<!-- 哪些用户有权配置提交任务优先级 -->
<property>
    <name>yarn.scheduler.capacity.root.hive.acl_application_max_priority</name>
    <value>*</value>
</property>

<!-- 任务的超时时间设置:yarn application -appId ***appId*** **-updateLifetime** ***Timeout***参
考资料:<https://blog.cloudera.com/enforcing-application-lifetime-slas-yarn/> -->
<!-- 如果application指定了超时时间,则提交到该队列的application能够指定的最大超时时间不能超过该值。-->

<property>
    <name>yarn.scheduler.capacity.root.hive.maximum-application-lifetime</name>
    <value>-1</value>
</property>

<!-- 如果application没指定超时时间,则用default-application-lifetime作为默认值 -->
<property>
    <name>yarn.scheduler.capacity.root.hive.default-application-lifetime</name>
    <value>-1</value>
</property>

<!-- 分发配置文件 -->
<!-- 重启Yarn或者执行yarn rmadmin -refreashQueues 刷新队列 -->
  • 向hive队列提交任务
# -D表示运行时改变参数值
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount -D 
mapreduce.job.queuename=hive /input /output

# 在java程序中修改相应的配置
conf.set("mapreduce.job.queuename", "hive");

任务优先级

  • yarn默认所有任务优先级为0,若想使用任务的优先级功能,需开放限制。
# 修改yarn-site.xml文件,增加以下参数
<property>
    <name>yarn.cluster.max-application-priority</name>
    <value>5</value>
</property>

# 分发配置,重启yarn

# 提交高优先级作业
hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar 
pi  -D mapreduce.job.priority=5 5 2000000

# 通过以下命令修改正在执行的任务的优先级
yarn application -appID application_1611133087930_0009 -updatePriority 5

公平调度器案例

  • yarn-site.xml中添加以下内容
<property>
  <name>yarn.resourcemanager.scheduler.class</name>
  <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value>
  <description>配置使用公平调度器</description>
</property>
<property>
  <name>yarn.scheduler.fair.allocation.file</name>
  <value>/usr/local/hadoop/hadoop-3.1.3/etc/hadoop/fair-scheduler.xml</value>
  <description>指明公平调度器队列分配配置文件</description>
</property>
<property>
  <name>yarn.scheduler.fair.preemption</name>
  <value>false</value>
  <description>禁止队列间资源抢占</description>
</property>
  • 新建fair-scheduler.xml,写入以下内容
<?xml version="1.0"?>
<allocations>
  <!-- 单个队列中Application Master占用资源的最大比例,取值0-1 ,企业一般配置0.1 -->
  <queueMaxAMShareDefault>0.5</queueMaxAMShareDefault>
  <!-- 单个队列最大资源的默认值 test root default -->
  <queueMaxResourcesDefault>4096mb,4vcores</queueMaxResourcesDefault>

  <!-- 增加一个队列test -->
  <queue name="test">
    <!-- 队列最小资源 -->
    <minResources>2048mb,2vcores</minResources>
    <!-- 队列最大资源 -->
    <maxResources>4096mb,4vcores</maxResources>
    <!-- 队列中最多同时运行的应用数,默认50,根据线程数配置 -->
    <maxRunningApps>4</maxRunningApps>
    <!-- 队列中Application Master占用资源的最大比例 -->
    <maxAMShare>0.5</maxAMShare>
    <!-- 该队列资源权重,默认值为1.0 -->
    <weight>1.0</weight>
    <!-- 队列内部的资源分配策略 -->
    <schedulingPolicy>fair</schedulingPolicy>
  </queue>
  <!-- 增加一个队列root -->
  <queue name="atguigu" type="parent">
    <!-- 队列最小资源 -->
    <minResources>2048mb,2vcores</minResources>
    <!-- 队列最大资源 -->
    <maxResources>4096mb,4vcores</maxResources>
    <!-- 队列中最多同时运行的应用数,默认50,根据线程数配置 -->
    <maxRunningApps>4</maxRunningApps>
    <!-- 队列中Application Master占用资源的最大比例 -->
    <maxAMShare>0.5</maxAMShare>
    <!-- 该队列资源权重,默认值为1.0 -->
    <weight>1.0</weight>
    <!-- 队列内部的资源分配策略 -->
    <schedulingPolicy>fair</schedulingPolicy>
  </queue>

  <!-- 任务队列分配策略,可配置多层规则,从第一个规则开始匹配,直到匹配成功 -->
  <queuePlacementPolicy>
    <!-- 提交任务时指定队列,如未指定提交队列,则继续匹配下一个规则; false表示:如果指定队列不存在,不允许自动创建-->
    <rule name="specified" create="false"/>
    <!-- 提交到root.group.username队列,若root.group不存在,不允许自动创建;若root.group.user不存在,允许自动创建 -->
    <rule name="nestedUserQueue" create="true">
        <rule name="primaryGroup" create="false"/>
    </rule>
    <!-- 最后一个规则必须为reject或者default。Reject表示拒绝创建提交失败,default表示把任务提交到default队列 -->
    <rule name="reject" />
  </queuePlacementPolicy>
</allocations>
  • 分发并重启yarn
  • 测试提交任务,指定队列名称
hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar pi -Dmapreduce.job.queuename=root.test 1 1

Yarn的Tool接口案例

  • 需求:希望能够在使用命令行运行自己编写的程序时,能够动态传参。
  • 实现: 使用yarn的Tool接口,ToolRunner类和Tool接口是Hadoop MapReduce框架的一部分,主要用于在Hadoop集群上运行MapReduce作业
  • Tool接口:是MapReduce作业的接口,定义了一个run方法,负责运行整个MapReduce作业。
  • ToolRunner类:是一个辅助类,用于运行实现了Tool接口的MapReduce作业。其中包含GenericOptionsParser对象,其getRemainingArgs()方法可获取除通用选项外的剩余命令行参数(用户自定义的选项)。
  • 创建WordCount并实现Tool接口
public class WordCount implements Tool {

    private Configuration conf;

    @Override
    public int run(String[] strings) throws Exception {
        Job job = Job.getInstance(conf);
        job.setJarByClass(WordCountDriver.class);
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReduce.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        FileInputFormat.setInputPaths(job, new Path(strings[0]));
        FileOutputFormat.setOutputPath(job, new Path(strings[1]));
        return job.waitForCompletion(true) ? 0 : 1;
    }

    @Override
    public void setConf(Configuration configuration) {
        conf = configuration;
    }

    @Override
    public Configuration getConf() {
        return conf;
    }

    public static 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, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
            String[] split = value.toString().split("\t");

            for (String s : split) {
                k.set(s);
                context.write(k, v);
            }
        }
    }


    public static class WordCountReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
        IntWritable v = new IntWritable();
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable value : values) {
                sum += value.get();
            }
            v.set(sum);
            context.write(key, v);
        }
    }

}
  • 创建WordCountDriver类,使用ToolRunner来运行Mapreduce程序
public class WordCountDriver {

    private static Tool tool;

    public static void main(String[] args) throws Exception {
        // 1.创建配置文件
        Configuration conf = new Configuration();

        // 2.判断是否有tool接口
        switch (args[0]) {
            case "wordcount":
                tool = new WordCount();
                break;
            default:
                throw new RuntimeException("no such tool " + args[0]);
        }

        String[] strings = Arrays.copyOfRange(args, 1, args.length);

        int run = ToolRunner.run(conf, tool, strings);
        System.exit(run);
    }
}
  • jar包上传集群,并使用命令行运行, 自定义参数指定作业提交的队列
yarn jar wc.jar com.atguigu.yarn.WordCountDriver wordcount -Dmapreduce.job.queuename=root.test /input /output9
  • hadoop jar与 yarn jar的区别
    • hadoop jar: 按mr或yarn运行job,取决于是否配置yarn,资源调度模式可能是local,也可能是yarn
    • yarn jar: 按照yarn运行job,资源调度是yarn

Yarn重点总结

  • Yarn工作机制(面试重点)
  • Yarn的调度器
    • FIFO/容量/公平
    • apache 默认调度器 容量, CDH默认调度器 公平
    • 公平/容量默认一个default队列,需要创建多队列
    • 中小企业,按作业类型创建队列: hive spark flink mr
    • 中大企业,按照业务模块创建队列:登录/注册/购物车/营销
    • 好处:解耦 降低风险, 11.11 6.18等特殊时期,可对不不同队列降级处理
    • 每个调度器的特点:
      • 相同点:支持多队列,可以借资源,支持对用户
      • 不同点:1)容量调度器:优先满足先进来的任务执行 2)公平调度器:在队列里面的任务公平享有队列资源
    • 生产环境怎么选:
      • 中小企业:对并发度要求不高,选择容量
      • 中大企业:对并发度要求较高,选择公平
  • 开发需要重点掌握:
    • 队列运行原理
    • Yarn常用命令
    • 核心参数配置
    • 配置容量调度器和公平调度器
    • tool接口使用