博客
关于我
从Container内存监控限制到CPU使用率限制方案
阅读量:384 次
发布时间:2019-03-05

本文共 4804 字,大约阅读时间需要 16 分钟。

前言

最近在运维我们部门的Hadoop集群时,发现了很多Job OOM的现象。频繁的Full GC导致了严重的性能问题。Full GC会导致“stop the world”,一旦Full GC的时间超过几分钟,其他活动都会受到影响。因此,必须找到原因并解决它。本文将介绍我们是如何解决这个问题,并在此基础上进行了一些优化。

Full GC源于何处

OOM的发生导致频繁的Full GC。首先需要确定具体原因。通常,第一个联想是上面的Job,Job的运行表现来自每个Task,而每个Task又表现为每个TaskAttempt。TaskAttempt运行在申请到的Container中。每个Container是一个独立的进程,可以通过jps命令在DataNode上看到大量名为“YarnChild”的进程,这些进程就是Container的启动进程。

初步估计是Container启动的JVM内存配置不足,导致内存不足。但问题并没有这么简单,这里还有些复杂。

为什么会发生Full GC

  • 内存配置不当:MapReduce任务的内存配置默认为1024MB(即1GB),但这可能不够,尤其是在处理大数据量或复杂任务时。错误的配置也可能导致JVM无法使用所需内存,从而引发OOM。

  • JVM配置错误:虽然mapreduce.map.memory.mbmapreduce.reduce.memory.mb是MapReduce任务的内存配置,但实际上它们并不是Container启动的JVM的内存配置。JVM的内存上限由mapreduce.map.java.optsmapreduce.reduce.java.opts决定。因此,理想的配置是java.opts的值必须大于等于memory.mb的值。如果配置不当,也会引发频繁的Full GC。

  • Container内存监控

    幸运的是,Hadoop已经对Container级别的内存进行了监控。对于所有启动的Container,Hadoop会额外启动一个名为container-monitor的线程,专门监控这些Container的物理内存和虚拟内存使用情况。相关的配置项包括:

    • yarn.nodemanager.pmem-check-enabled
    • yarn.nodemanager.vmem-check-enabled

    默认情况下,这两项都启用。内存监控的作用是一旦Container使用的内存超过JVM的最大内存上限,Container会被杀死。

    通过分析ContainersMonitorImpl.java可以看出,监控线程会在每隔一定时间(由YarnConfiguration.NM_CONTAINER_MON_INTERVAL_MS控制)遍历所有被监控的Container,检查它们的内存使用情况。如果内存使用超过限制,Container会被杀死。

    为什么只对Container内存做监控

    在解决上述问题后,我开始思考为什么不对CPU使用率也进行监控。同样重要的指标,CPU使用率为什么不一起监控呢?

    我总结了以下几点原因:

  • 影响更大:内存问题比CPU使用率问题影响更大,因为OOM会导致Full GC,一旦发生Full GC,整个应用都会受到影响。
  • 更常见:内存问题比CPU使用率问题更常见。大家在日常生活或编写程序时,更容易遇到内存不足的问题,而不是CPU不足的问题。
  • 密切相关:内存使用与Job处理的数据量密切相关。处理大数据量的Job,内存使用自然会更多,CPU使用率也会增加,但不会那么明显。
  • 综上所述,CPU监控并未被加入到监控代码中(个人分析)。但Hadoop自身并未加CPU监控并不代表我们不能添加这样的监控功能。例如,对于那些内存并不多,但会耗尽大量CPU资源的程序(如开很多线程但每个线程都做简单操作的程序),添加CPU使用率监控会有帮助。

    Container的Cpu使用率监控

    为了实现对CPU使用率的监控,我们需要:

  • 定义是否启用CPU使用率监控的配置:
  • /** Specifies whether cpu vcores check is enabled. */public static final String NM_VCORES_CHECK_ENABLED = NM_PREFIX + "vcores-check-enabled";public static final boolean DEFAULT_NM_VCORES_CHECK_ENABLED = false;

    默认情况下,CPU使用率监控是关闭的。同时,还需要定义一个使用阈值(0~1之间),一旦某个Container的CPU使用率超过这个阈值,Container就会被杀死。

    1. 定义CPU使用率的限制比例:
    2. /** Limit ratio of Virtual CPU Cores which can be allocated for containers. */public static final String NM_VCORES_LIMITED_RATIO = NM_PREFIX + "resource.cpu-vcores.limited.ratio";public static final float DEFAULT_NM_VCORES_LIMITED_RATIO = 0.8f;

      默认值为0.8,可以根据需要进行调整。

      1. serviceInit方法中进行配置初始化:
      2. private boolean pmemCheckEnabled;private boolean vmemCheckEnabled;private boolean vcoresCheckEnabled;private float vcoresLimitedRatio;...pmemCheckEnabled = conf.getBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, YarnConfiguration.DEFAULT_NM_PMEM_CHECK_ENABLED);vmemCheckEnabled = conf.getBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, YarnConfiguration.DEFAULT_NM_VMEM_CHECK_ENABLED);vcoresCheckEnabled = conf.getBoolean(YarnConfiguration.NM_VCORES_CHECK_ENABLED, YarnConfiguration.DEFAULT_NM_VCORES_CHECK_ENABLED);LOG.info("Physical memory check enabled: " + pmemCheckEnabled);LOG.info("Virtual memory check enabled: " + vmemCheckEnabled);LOG.info("Cpu vcores check enabled: " + vcoresCheckEnabled);if (vcoresCheckEnabled) {    vcoresLimitedRatio = conf.getFloat(YarnConfiguration.NM_VCORES_LIMITED_RATIO, YarnConfiguration.DEFAULT_NM_VCORES_LIMITED_RATIO);    LOG.info("Vcores limited ratio: " + vcoresLimitedRatio);}
        1. 在监控代码中使用计算出的CPU使用率进行判断:
        2. LOG.debug("Constructing ProcessTree for : PID = " + pId + " ContainerId = " + containerId);ResourceCalculatorProcessTree pTree = ptInfo.getProcessTree();pTree.updateProcessTree();long currentVmemUsage = pTree.getVirtualMemorySize();long currentPmemUsage = pTree.getRssMemorySize();// if machine has 6 cores and 3 are used, // cpuUsagePercentPerCore should be 300% and // cpuUsageTotalCoresPercentage should be 50%float cpuUsagePercentPerCore = pTree.getCpuUsagePercent();float cpuUsageTotalCoresPercentage = cpuUsagePercentPerCore / resourceCalculatorPlugin.getNumProcessors();
          1. 在核心逻辑中进行判断:
          2. } else if (isVcoresCheckEnabled() && cpuUsageTotalCoresPercentage > vcoresLimitedRatio) {    msg = String.format(        "Container [pid=%s,containerID=%s] is running beyond %s vcores limits."            + " Current usage: %s. Killing container.\n", pId,        containerId, vcoresLimitedRatio);    isCpuVcoresOverLimit = true;    containerExitStatus = ContainerExitStatus.KILLED_EXCEEDED_VCORES;}if (isMemoryOverLimit || isCpuVcoresOverLimit) {    // Virtual or physical memory over limit. Fail the container and    // remove the corresponding process tree    LOG.warn(msg);    // warn if not a leader    if (!pTree.checkPidPgrpidForMatch()) {        LOG.error("Killed container process with PID " + pId            + " but it is not a process group leader.");    }    // kill the container    eventDispatcher.getEventHandler().handle(        new ContainerKillEvent(containerId, containerExitStatus, msg));    it.remove();    LOG.info("Removed ProcessTree with root " + pId);} else {

            相关链接

    转载地址:http://gvng.baihongyu.com/

    你可能感兴趣的文章
    nodejs框架,原理,组件,核心,跟npm和vue的关系
    查看>>
    Nodejs模块、自定义模块、CommonJs的概念和使用
    查看>>
    nodejs生成多层目录和生成文件的通用方法
    查看>>
    nodejs端口被占用原因及解决方案
    查看>>
    Nodejs简介以及Windows上安装Nodejs
    查看>>
    nodejs系列之express
    查看>>
    nodejs系列之Koa2
    查看>>
    Nodejs连接mysql
    查看>>
    nodejs连接mysql
    查看>>
    NodeJs连接Oracle数据库
    查看>>
    nodejs配置express服务器,运行自动打开浏览器
    查看>>
    Nodemon 深入解析与使用
    查看>>
    node不是内部命令时配置node环境变量
    查看>>
    node中fs模块之文件操作
    查看>>
    Node中同步与异步的方式读取文件
    查看>>
    Node中的Http模块和Url模块的使用
    查看>>
    Node中自启动工具supervisor的使用
    查看>>
    Node入门之创建第一个HelloNode
    查看>>
    node全局对象 文件系统
    查看>>
    Node出错导致运行崩溃的解决方案
    查看>>