Winse Blog

走走停停都是风景, 熙熙攘攘都向最好, 忙忙碌碌都为明朝, 何畏之.

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。

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

一个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)。

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

1
2
3
4
5
6
7
8
9
[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 打断点,然后跑任务:

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

AppMaster内存分配:

Executor内存分配:

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

具体代码调度过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  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

Comments