YARN多资源队列配置和使用

一. YARN的由来

从Hadoop2开始,官方把资源管理单独剥离出来,主要是为了考虑后期作为一个公共的资源管理平台,任何满足规则的计算引擎都可以在它上面执行。

所以YARN可以是实现Hadoop集群的资源共享,不仅仅可以跑MapReduce,还可以跑Spark,Flink。

二.YARN架构

YARN主要负责集群资源的管理和调度,支持主从架构,主节点最多可以有2个,从节点可以有多个.

其中:

ResourceManager: 这是主节点,主要负责集群资源的分配和管理

NodeManager:这是从节点,主要负责当前机器资源管理

三.YARN资源管理模型

YARN主要管理内存和CPU这两种资源

当NodeManager节点启动的时候自动向ResourceManager注册,将当前节点上的可用CPU信息和内存信息注册上去。

这样所有的NodeManager注册完成以后,ResourceManager就知道目前集群的资源总量了。

打开YARN的8088管理界面

注意:这里面显示的资源是所有从节点的资源总和,不包括主节点的资源。
YARN的内存和CPU总量在 yarn-default.xml 通过以下两个参数配置:

(1) yarn.nodemanager.resource.memory-mb : 单节点可分配的物理内存总量,默认8G

(2) yarn.nodemanager.resource.cpu-vcores : 单节点可分配的虚拟CPU个数,默认8个

四.YARN的调度器

大家可以想象一下,我们集群的资源是有限的,在实际工作中会有很多人向集群提交任务,那这时候资源如何分配呢?

如果你提交了一个很占资源的任务,这一个任务就把集群中90%的资源都占用了,后面别人提交任务,剩下的资源就不够了,这时候怎么办?

YARN支持3中调度器:

(1)  FIFO  Scheduler : 先进先出(first in , first out)调度策略

  (2)    Capacity Scheduler : FIFO Scheduler的多多列版本

  (3)    FairScheduler : 多队列,多用户共享资源

(1)  FIFO  Scheduler : 先进先出,大家都按顺序排队,如果你的任务申请不到足够的资源,你就等着,等前面执行完了释放资源之后你再执行。这种在有些时候不合理,因为我们有一些任务的优先级比较高,我们希望任务提交上去就立刻开始执行,这个就实现不了了。

(2)    Capacity Scheduler : FIFO  Scheduler的多队列版本,我们把集群的资源分成多个队列。如图我们可以在queueA里面运行普通任务,在queueB中运行优先级比较高的任务。队列之间都是相互独立的。

(3)    FairScheduler : 支持多队列,每个队列可配置一定的资源,每个队列共享所分的所有资源,假设我们向一个队列提交了一个任务,这个任务刚开始会占用整个队列的资源,当你再提交第二个任务的时候,第一个任务会把他的资源释放出来一部分给第二个任务使用。

在实际工作中我们一般使用(2)    Capacity Scheduler,从hadoop2开始,Capacity Scheduler也是默认调度器。

五.YARN多资源队列配置和使用

我们增加2个队列,一个是online队列,一个是offline队列

然后向offline队列中提交一个mapreduce任务

online队列里面运行实时任务

offline队列里面运行离线任务

具体步骤如下:

(1) 修改 $HADOOP_HOME下的capacity-scheduler.xml配置文件

修改和增加以下参数,针对已有的参数,修改value中的值,针对没有的参数,则直接增加

这里的default是需要保留的,增加online,offline.

[root@bigdata01 hadoop]# vim capacity-scheduler.xml
  <property>
    <name>yarn.scheduler.capacity.root.queues</name>
    <value>default
,online,offline</value>
    <description>队列列表,多个队列之间使用逗号分割</description>
  </property>
  <property>

    <name>yarn.scheduler.capacity.root.default.capacity</name>
    <value>70</value>
    <description>default队列70%</description>
  </property>
  <property>

    <name>yarn.scheduler.capacity.root.online.capacity</name>
    <value>10</value>
    <description>online队列10%</description>
  </property>
  <property>
    <name>yarn.scheduler.capacity.root.offline.capacity</name>
    <value>20</value>
    <description>offline队列20%</description>
  </property>

  <property>
    <name>yarn.scheduler.capacity.root.default.maximum-capacity</name>
    <value>70</value>
    <description>Default队列可使用的资源上限.</description>
  </property>

  <property>
    <name>yarn.scheduler.capacity.root.online.maximum-capacity</name>
    <value>10</value>
    <description>online队列可使用的资源上限.</description>
  </property>
  <property>
    <name>yarn.scheduler.capacity.root.offline.maximum-capacity</name>
    <value>20</value>
    <description>offline队列可使用的资源上限.</description>
  </property>

记得每个节点都需要修改,然后重启集群后生效。

注意了,现在默认提交的任务还是会进入default队列,如果希望向offline队列提交任务的话,需要指定队列名称,不指定就进入默认队列。

package com.imooc.mr;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * 指定队列名称
 *
 * Created by xuwei
 */
public class WordCountJobQueue {
    /**
     * Map阶段
     */
    public static class MyMapper extends Mapper<LongWritable, Text,Text,LongWritable>{
        Logger logger = LoggerFactory.getLogger(MyMapper.class);
        /**
         * 需要实现map函数
         * 这个map函数就是可以接收<k1,v1>,产生<k2,v2>
         * @param k1
         * @param v1
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        @Override
        protected void map(LongWritable k1, Text v1, Context context)
                throws IOException, InterruptedException {
            //输出k1,v1的值
            //System.out.println("<k1,v1>=<"+k1.get()+","+v1.toString()+">");
            //logger.info("<k1,v1>=<"+k1.get()+","+v1.toString()+">");
            //k1 代表的是每一行数据的行首偏移量,v1代表的是每一行内容
            //对获取到的每一行数据进行切割,把单词切割出来
            String[] words = v1.toString().split(" ");
            //迭代切割出来的单词数据
            for (String word : words) {
                //把迭代出来的单词封装成<k2,v2>的形式
                Text k2 = new Text(word);
                LongWritable v2 = new LongWritable(1L);
                //把<k2,v2>写出去
                context.write(k2,v2);
            }
        }
    }


    /**
     * Reduce阶段
     */
    public static class MyReducer extends Reducer<Text,LongWritable,Text,LongWritable>{
        Logger logger = LoggerFactory.getLogger(MyReducer.class);
        /**
         * 针对<k2,{v2...}>的数据进行累加求和,并且最终把数据转化为k3,v3写出去
         * @param k2
         * @param v2s
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        @Override
        protected void reduce(Text k2, Iterable<LongWritable> v2s, Context context)
                throws IOException, InterruptedException {
            //创建一个sum变量,保存v2s的和
            long sum = 0L;
            //对v2s中的数据进行累加求和
            for(LongWritable v2: v2s){
                //输出k2,v2的值
                //System.out.println("<k2,v2>=<"+k2.toString()+","+v2.get()+">");
                //logger.info("<k2,v2>=<"+k2.toString()+","+v2.get()+">");
                sum += v2.get();
            }

            //组装k3,v3
            Text k3 = k2;
            LongWritable v3 = new LongWritable(sum);
            //输出k3,v3的值
            //System.out.println("<k3,v3>=<"+k3.toString()+","+v3.get()+">");
            //logger.info("<k3,v3>=<"+k3.toString()+","+v3.get()+">");
            // 把结果写出去
            context.write(k3,v3);
        }
    }

    /**
     * 组装Job=Map+Reduce
     */
    public static void main(String[] args) {
        try{

            //指定Job需要的配置参数
            Configuration conf = new Configuration();
            //解析命令行中-D后面传递过来的参数,添加到conf中
            String[] remainingArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

            //创建一个Job
            Job job = Job.getInstance(conf);


            //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的
            job.setJarByClass(WordCountJobQueue.class);
            
            //指定输入路径(可以是文件,也可以是目录)
            FileInputFormat.setInputPaths(job,new Path(remainingArgs[0]));
            //指定输出路径(只能指定一个不存在的目录)
            FileOutputFormat.setOutputPath(job,new Path(remainingArgs[1]));

            //指定map相关的代码
            job.setMapperClass(MyMapper.class);
            //指定k2的类型
            job.setMapOutputKeyClass(Text.class);
            //指定v2的类型
            job.setMapOutputValueClass(LongWritable.class);




            //指定reduce相关的代码
            job.setReducerClass(MyReducer.class);
            //指定k3的类型
            job.setOutputKeyClass(Text.class);
            //指定v3的类型
            job.setOutputValueClass(LongWritable.class);

            //提交job
            job.waitForCompletion(true);
        }catch(Exception e){
            e.printStackTrace();
        }

    }


}

 //解析命令行中-D后面传递过来的参数,添加到conf中
String[] remainingArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

将JAVA代码编译打包,上传到服务器。

[root@bigdata01 hadoop-3.2.0]# hadoop jar db_hadoop-1.0-SNAPSHOT-jar-with-dependencies.jar com.imooc.mr.WordCountJobQueue -Dmapreduce.job.queuename=offline /test/hello.txt /outqueue

可以看到YARN根据我们指定的队列名称执行了任务。


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值