跳到正文
W Winse Blog
bigdata 2 min read

spark-on-yarn内存分配

上次写了一篇关于配置参数是如何影响mapreduce的实际调度的参考

  • opts(yarn.app.mapreduce.am.command-opts、mapreduce.map.java.opts、mapreduce.reduce.java.opts)是实际运行程序是内存参数。
  • memory(yarn.app.mapreduce.am.resource.mb、mapreduce.map.memory.mb、mapreduce.reduce.memory.mb)是用于ResourceManager计算集群资源使用和调度。

了解参数区别,就没有再深究task内存的问题了。

# 新问题-内存分配

这次又遇到内存问题:spark使用yarn-client的方式运行时,spark有memoryOverhead的设置,但是加了额外的内存后,再经过集群调度内存浪费严重,对于本来就小内存的集群来说完全无法接受。

  • am默认是512加上384 overhead,也就是896m。但是调度后am分配内存资源为1024。
  • executor默认是1024加上384,等于1408M。单调度后executor分配内存资源为2048。

[hive-on-spark-memory-allocate-0.png 图片]

从appmaster的日志可以看出来请求的内存大小是1408:

[hive-on-spark-memory-allocate-1.png 图片]

一个executor就浪费了500M,本来可以跑4个executor的但现在只能执行3个!

关于内存参数的具体含义查看官网: spark-on-yarnyarn-default.xml

|| 参数 ||
||:---------------------------------------:||:-------------------------------------------- || spark.yarn.am.memory || 512m
|| spark.driver.memory || 1g
|| spark.yarn.executor.memoryOverhead || executorMemory * 0.10, with minimum of 384
|| spark.yarn.driver.memoryOverhead || driverMemory * 0.10, with minimum of 384
|| spark.yarn.am.memoryOverhead || AM memory * 0.10, with minimum of 384
|| yarn.nodemanager.resource.memory-mb || 8192
|| yarn.scheduler.minimum-allocation-mb || 1024
|| yarn.scheduler.maximum-allocation-mb || 8192

分配的内存看着像是 最小分配内存 的整数倍。把 yarn.scheduler.minimum-allocation-mb 修改为512,重启yarn再运行,executor的分配的内存果真减少到1536(512*3)。

[hive-on-spark-memory-allocate-3.png 图片]

同时 http://blog.javachen.com/2015/06/09/memory-in-spark-on-yarn.html 这篇文章也讲 在YARN中,Container申请的内存大小必须为yarn.scheduler.minimum-allocation-mb的整数倍 。我们不去猜,调试下调度代码,看看究竟是什么情况。

[hadoop@cu2 hadoop-2.6.3]$ sbin/yarn-daemon.sh stop resourcemanager 

[hadoop@cu2 hadoop]$ grep "minimum-allocation-mb" -1 yarn-site.xml 
<property>
<name>yarn.scheduler.minimum-allocation-mb</name><value>512</value>
</property>

[hadoop@cu2 hadoop-2.6.3]$ export YARN_RESOURCEMANAGER_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000"
[hadoop@cu2 hadoop-2.6.3]$ sbin/yarn-daemon.sh start resourcemanager 

本地eclipse在 CapacityScheduler#allocate 打断点,然后跑任务:

hive> set hive.execution.engine=spark;
hive> select count(*) from t_ods_access_log2 where month=201512;

AppMaster内存分配:

[hive-on-spark-memory-allocate-appmaster.png 图片]

Executor内存分配:

[hive-on-spark-memory-allocate-executor.png 图片]

request进到allocate后,最终调用 DefaultResourceCalculator.normalize 重新计算了一遍请求需要的资源,把内存调整了。默认的DefaultResourceCalculator可以通过 capacity-scheduler.xml 的 yarn.scheduler.capacity.resource-calculator 来修改。

具体代码调度过程如下:

  public Allocation allocate(ApplicationAttemptId applicationAttemptId,
      List<ResourceRequest> ask, List<ContainerId> release, 
      List<String> blacklistAdditions, List<String> blacklistRemovals) {
    ...
    // Sanity check
    SchedulerUtils.normalizeRequests(
        ask, getResourceCalculator(), getClusterResource(),
        getMinimumResourceCapability(), maximumAllocation);
...

  public static void normalizeRequest(
      ResourceRequest ask, 
      ResourceCalculator resourceCalculator, 
      Resource clusterResource,
      Resource minimumResource,
      Resource maximumResource,
      Resource incrementResource) {
    Resource normalized = 
        Resources.normalize(
            resourceCalculator, ask.getCapability(), minimumResource,
            maximumResource, incrementResource);
    ask.setCapability(normalized);
  }	
...

  public static Resource normalize(
      ResourceCalculator calculator, Resource lhs, Resource min,
      Resource max, Resource increment) {
    return calculator.normalize(lhs, min, max, increment);
  }
...

  public Resource normalize(Resource r, Resource minimumResource,
      Resource maximumResource, Resource stepFactor) {
    int normalizedMemory = Math.min(
        roundUp(
            Math.max(r.getMemory(), minimumResource.getMemory()),
            stepFactor.getMemory()),
            maximumResource.getMemory());
    return Resources.createResource(normalizedMemory);
  }
...

  public static int roundUp(int a, int b) {
    return divideAndCeil(a, b) * b;
  }
  

# 小结

今天又重新认识一个yarn参数 yarn.scheduler.minimum-allocation-mb ,不仅仅是最小分配的内存,同时分配的资源也是minimum-allocation-mb的整数倍,还告诉我们 yarn.nodemanager.resource.memory-mb 也最好是minimum-allocation-mb的整数倍。

间接的学习了新的参数,可以通过 yarn.scheduler.capacity.resource-calculator 参数 来修改 CapacityScheduler 调度器的资源计算类。

–END

在 GitHub 上讨论

欢迎通过 GitHub Issue 留言或反馈。每条讨论都会关联到对应文章的源文件路径。

2016-04-11-spark-on-yarn-memory-allocate.md

Related posts