基于原生hadoop的多租户开发与xpath解析xml

上一篇文章讲到需要修改远程服务器的一些配置文件,其实这个场景需要修改的配置文件是原生hadoop的yarn-site.xml文件,目的是基于原生hadoop实现多租户,多租户其实就是在提交任务时根据不同的用户和组分配不同的计算资源,说白了就是修改一些配置文件,yarn-site.xml会根据yarn.scheduler.fair.allocation.file这个属性找到我们fair-scheduler.xml定义的调度策略与具体每个资源池的大小。本次我只要使用的资源调度方式是fair-scheduler的方式,下面来看一下官网文档的介绍:

介绍

公平调度是一种为应用程序分配资源的方法,使得所有应用程序平均可以随时间获得相等的资源份额。Hadoop NextGen能够调度多种资源类型。默认情况下,公平调度程序仅根据内存来确定调度公平性决策。它可以配置为使用Ghodsi等人开发的Dominant Resource Fairness概念同时调度内存和CPU。当有一个应用程序在运行时,该应用程序将使用整个群集。当提交其他应用程序时,释放的资源将分配给新应用程序,以便最终每个应用程序获得大致相同的资源量。与构成应用程序队列的默认Hadoop调度程序不同,这可以让短应用程序在合理的时间内完成,同时不会使长期存在的应用程序挨饿。它也是在多个用户之间共享群集的合理方式。最后,公平共享还可以与应用优先级一起使用 - 优先级用作权重来确定每个应用应获得的总资源的比例。

调度程序将应用程序进一步组织为“队列”,并在这些队列之间公平地共享资源。默认情况下,所有用户共享一个名为“default”的队列。如果应用程序专门在容器资源请求中列出队列,则将请求提交给该队列。还可以通过配置基于请求中包含的用户名来分配队列。在每个队列中,调度策略用于在正在运行的应用程序之间共享资源。默认值是基于内存的公平共享,但也可以配置具有显性资源公平性的FIFO和多资源。可以按层次结构排列队列以划分资源,并使用权重配置以按特定比例共享群集。

除了提供公平共享之外,Fair Scheduler还允许为队列分配保证的最小份额,这对于确保某些用户,组或生产应用程序始终获得足够的资源非常有用。当队列包含应用程序时,它至少获得其最小份额,但是当队列不需要其完全保证共享时,超出部分将在其他正在运行的应用程序之间分配。这使得调度程序可以保证队列容量,同时在这些队列不包含应用程序时有效利用资源。

Fair Scheduler允许所有应用程序默认运行,但也可以通过配置文件限制每个用户和每个队列运行的应用程序数量。当用户必须一次提交数百个应用程序时,这可能很有用,或者一般来说,如果同时运行太多应用程序会导致创建过多的中间数据或过多的上下文切换,则可以提高性能。限制应用程序不会导致任何后续提交的应用程序失败,只会在调度程序的队列中等待,直到某些用户的早期应用程序完成为止。

yarn-site.xml中可以配置的属性:

下面给出一个yarn-site.xml的配置范例:

  <property> 
    <name>yarn.resourcemanager.scheduler.class</name>  
    <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler</value> 
  </property>  
  <property> 
    <name>yarn.scheduler.fair.max.assign</name>  
    <value>-1</value> 
  </property>  
  <property> 
    <name>yarn.scheduler.fair.locality.threshold.rack</name>  
    <value>0.1</value> 
  </property>  
  <property> 
    <name>yarn.acl.enable</name>  
    <value>true</value> 
  </property>  
  <property> 
    <name>yarn.scheduler.fair.assignmultiple</name>  
    <value>true</value> 
  </property>  
  <property> 
    <name>yarn.scheduler.fair.allocation.file</name>  
    <value>fair-scheduler.xml存放的路径</value>
</property>  
  <property> 
    <name>yarn.scheduler.fair.user-as-default-queue</name>  
    <value>false</value> 
  </property>  
  <property> 
    <name>yarn.scheduler.fair.preemption</name>  
    <value>true</value> 
  </property>  
  <property> 
    <name>yarn.scheduler.fair.sizebasedweight</name>  
    <value>true</value> 
  </property>  
  <property> 
    <name>yarn.admin.acl</name>  
    <value>*</value> 
  </property>  
  <property> 
    <name>yarn.scheduler.fair.locality.threshold.node</name>  
    <value>0.1</value> 
  </property> 

fair-scheduler当中可配置的属性:

fair-scheduler.xml配置范例:

<?xml version="1.0" encoding="UTF-8"?>

<allocations>
    <queue name="root">
        <minResources>10000mb,10vcores</minResources>
        <maxResources>90000mb,100vcores</maxResources>
        <maxRunningApps>50</maxRunningApps>
        <weight>2.0</weight>
        //子队列也可以自定义调度策略,“fifo”/“fair”/“drf”
        <schedulingPolicy>fair</schedulingPolicy>
        <aclSubmitApps/>
        <aclAdministerApps/>
        <queue name="default">
            <minResources>2000mb,1vcores</minResources>
            <maxResources>10000mb,1vcores</maxResources>
            <maxRunningApps>1</maxRunningApps>
            <schedulingMode>fair</schedulingMode>
            <weight>0.5</weight>
            <aclSubmitApps>*</aclSubmitApps>
        </queue>
        <queue name="queue1">
            <minResources>10000mb,10vcores</minResources>
            <maxResources>90000mb,100vcores</maxResources>
            <maxRunningApps>50</maxRunningApps>
            <weight>2.0</weight>
            <schedulingMode>fair</schedulingMode>
            <aclAdministerApps>datadev,admins datadev,admins</aclAdministerApps>
            // 这个配置的格式: user1,user2 [空格] group1,group2
            <aclSubmitApps>datadev,admins datadev,admins</aclSubmitApps>
        </queue>
    </queue>
    <user name="user1">
        <maxRunningApps>30</maxRunningApps>
    </user>
    <userMaxAppsDefault>5</userMaxAppsDefault>
    <queuePlacementPolicy>
        <rule name="specified"/>
        <rule name="primaryGroup" create="false"/>
        <rule name="nestedUserQueue"/>
        <rule name="secondaryGroupExistingQueue" create="false"/>
        <rule name="default" queue="sample_queue"/>
    </ queuePlacementPolicy>
</allocations>

或者直接参考官网文档:http://hadoop.apache.org/docs/stable/hadoop-yarn/hadoop-yarn-site/FairScheduler.html

因为需求是用户需要可视化的方式来配置这些,那就难免会遇到修改xml的问题,看了这些配置文件我们会发现这个xml并不是特别规范,层级不确定,很久之前就用过dom4j解析,感觉很麻烦,但是通过在网上查找资料发现一个特别好用的方法,就是利用xPath,下面直接拿我写的一个功能举例子吧:

添加或者修改资源池:

//通过要创建或者修改的资源池的层数来获取相应的xPath,我规定的是root的层级是1,那么default就是2,以此类推...    
public static String xPath(int n){
        String xPath = "/allocations";
        for (int i = 1; i < n; i++) {
            xPath += "/queue";
        }
        return xPath;
    }


//path:xml路径
//map:map的key是标签,value是标签的值
//childName:修改或者增加资源池的name的值
//parentName:上级的name值
//childXPath:修改或者增加资源池的xPath的值
//parentXPath:上级xPath的值
    public static void getAddOrUpdate(String path, Map map, String childName, String parentName, String childXPath, String parentXPath) {
        Boolean flag = true;
        File file = new File(path);
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(file);
            Element element = null;
            List list = document.selectNodes(childXPath);
            for (int i = 0; i < list.size(); i++) {
                Element e = (Element) list.get(i);
//如果有资源池的name等于childName,那么就说明是修改
                if (childName.equals(e.attribute("name").getValue())) {
                    flag = false;
                    element = e;
                    break;
                }
            }
//如果没找到就说明没有,那就是创建,创建的话就需要parentXPath来进行创建
            if (flag) {
                List list1 = document.selectNodes(parentXPath);
                for (int j = 0; j < list1.size(); j++) {
                    Element e1 = (Element) list1.get(j);
                    if (parentName.equals(e1.attribute("name").getValue())) {
                        element = e1;
                    }
                }
            }
            if (flag) {
//添加资源池
                updateAndAddQueue(document, element, map, childName, "create", file);
            } else {
//创建资源池
                updateAndAddQueue(document, element, map, childName, "update", file);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

//添加或修改
public static void updateAndAddQueue(Document document, Element element, Map<String, String> map, String queueName, String ags, File file) {
        Set<String> set = map.keySet();
        if (ags.equals("create")) {
            Element attribute = element.addElement("queue").addAttribute("name", queueName);
            for (String o : set) {
                attribute.addElement(o).setText(map.get(o));
            }
        } else {
            for (String o : set) {
                if (element.element(o) != null) {
                    element.element(o).setText(map.get(o));
                } else {
                    element.addElement(o).setText(map.get(o));
                }
            }
        }
        xmlWrite(document, file);
    }


//写入xml文件

   public static void xmlWrite(Document document, File file) {
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        try {
            XMLWriter writer = new XMLWriter(new FileWriter(file), format);
            writer.write(document);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

用到的maven依赖:

      <dependency>
          <groupId>dom4j</groupId>
          <artifactId>dom4j</artifactId>
          <version>1.6.1</version>
      </dependency>
      <dependency>
          <groupId>jaxen</groupId>
          <artifactId>jaxen</artifactId>
          <version>1.1.6</version>
      </dependency>

注意:动态更新只支持修改资源池配额,修改完毕之后需要使用命令:yarn rmadmin –refreshQueues来刷新资源池,

更改用户限制则需要使用命令:yarn rmadmin -refreshUserToGroupsMappings来刷新

如果是新增或减少资源池,则需要重启Yarn集群。

另外附上自己通过java重启yarn的代码:

    public static int restart(Long userId) {
        String[] stopCmd = {"bash", "-c", "sbin/stop-yarn.sh"};
        ProcessBuilder processBuilder = new ProcessBuilder(stopCmd);
        processBuilder.redirectErrorStream(true);
        processBuilder.directory(new File(“hadoop路径”));
        try {
            Process process = processBuilder.start();
            int i = process.waitFor();
            int i1 = startRM(userId);
            if (i == i1 && i == 0) {
                return 1;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static int startRM(Long userId) {
        String[] startCmd = {"bash", "-c", "sbin/start-yarn.sh"};
        ProcessBuilder processBuilder = new ProcessBuilder(startCmd);
        processBuilder.redirectErrorStream(true);
        processBuilder.directory(new File(“hadoop路径”));
        try {
            Process process = processBuilder.start();
            int i = process.waitFor();
            return i;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 1;
    }

代码可能有很多可以完善的地方,希望大家多提建议!!!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值