Spark _on_Yarn 資源池內存限制測試報告 - 防止"非法"任務的提交

需求背景

講道理,用戶在提交 Spark_on_yarn 任務 時,應該指定--executor-memory屬性(公司自己的規定),並且使用特定的用戶提交,以便於 DBA 的管理。但是仍然存在一些用戶直接使用 root 賬戶提交任務,這樣在 yarn 的資源池中就會被分配到 root.user.root池中,如果集羣壓力過大,那麼便不能迅速的找到該任務 的所有者,從而可能會對其它 team 的任務照成影響,基於此, 決定對資源池root.user.root進行內存限制,爲了防止確定其是否有用,同時防止直接修改線上環境配置會對已有的任務造成的影響,特做此簡單的測試。

環境配置

環境:
- yarn 2.6.0+cdh5.8.3+1718
- spark_on_yarn 1.6.0+cdh5.8.3+232

工具:
- Cloudera Manager

可執行文件:
- 自定義 jar 包,最終生成的名稱爲spark-mock-0.0.1-SNAPSHOT.jar,源碼如下:

package com.xxx.xxx.sparkmock;

import java.util.ArrayList;
import java.util.List;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.Function2;

public final class JavaSparkPi {

    @SuppressWarnings("serial")
    public static void main(String[] args) throws Exception {
        SparkConf sparkConf = new SparkConf().setAppName("JavaSparkPi");
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);

        int slices = 2;
        int n = 100000 * slices;
        List<Integer> l = new ArrayList<Integer>(n);
        for (int i = 0; i < n; i++) {
            l.add(i);
        }

        JavaRDD<Integer> dataSet = jsc.parallelize(l, slices);

        int count = dataSet.map(new Function<Integer, Integer>() {
            public Integer call(Integer v1) {
                double x = Math.random() * 2 - 1;
                double y = Math.random() * 2 - 1;
                return (x * x + y * y < 1) ? 1 : 0;
            }
        }).reduce(new Function2<Integer, Integer, Integer>() {
            public Integer call(Integer v1, Integer v2) {
                return v1 + v2;
            }
        });

        System.out.println("Pi is roughly " + 4.0 * count / n);
        jsc.stop();
    }
}

測試流程:

1. 將 jar 包拷貝至 hadoop 集羣,使用類似如下格式執行:

spark-submit --master yarn --executor-memory 512M  ~/spark-mock-0.0.1-SNAPSHOT.jar

提交用戶默認爲 kt94(登錄)

  • –master 指定任務基於 yarn 工作
  • –executor-memory 執行時的內存大小

2. 在 Cloudera Manager 中,配置資源池的容量大小,界面示例如下:

資源池配置界面_1
資源池配置界面_2

3. 反覆提交執行與更改配置,並觀察結果

測試結果

注 1:以下測試僅測試提交時申請的 AM 內存大小與配置的最大內存大小關係,暫未考慮權重(Weight)的影響,後面總結會提到權重。

注 2:--executor-memory是指定的執行內存,但是因爲存在額外的管理開銷,所以實際的AM 使用內存會大於--executor-memory指定的值,而配置的內存限制的是AM 的使用內存,所以下方比較的是AM memorymax memory(限制的最大內存)。

1. 默認情況下,即不指定--executor-memory時,會拋出以下異常:

// ...

java.lang.IllegalArgumentException: Required executor memory (1024+384 MB) is above the max threshold (1024 MB) of this cluster! Please check the values of 'yarn.scheduler.maximum-allocation-mb' and/or 'yarn.nodemanager.resource.memory-mb'.

// ...

這是由於測試環境的配置引起的,因爲請求時默認的executor-memory值爲1 GB,加上運行時所需的額外的384 MB,超出了閾值 1024 MB,所以拋出了異常,但是正式環境下,不會有這麼小的閾值,所以把--executor-memory設置爲更小的值繼續觀察。

2. 提交時指定--executor-memory=512M,資源池kt94設置Memory (Min / Max) ~= 100MiB / 5GiB時,即AM memory < max memory時,運行正常,資源池使用情況如下圖:

這裏寫圖片描述

AM 被分配3GiB的容量,小於5GiB

3. 提交時指定--executor-memory=512M,資源池kt94設置Memory (Min / Max) ~= 100MiB / 256MiB時,即AM memory > max memory時,任務一直處於ACCEPTED狀態,部分打印信息如下:

18/01/19 00:33:39 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:40 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:41 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:42 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:43 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:44 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:45 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:46 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:47 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)
18/01/19 00:33:48 INFO yarn.Client: Application report for application_1512525158468_0035 (state: ACCEPTED)

同時資源池kt94,該任務 一直在Pending Containers(待定的容器)中,資源池狀態示例如下圖所示:

這裏寫圖片描述

任務簡介如下圖所示:

這裏寫圖片描述

這裏寫圖片描述

此時並未分配內存給該任務,而該任務則一直處於ACCEPTED狀態,說明配置是生效的。

4. 重新配置使Memory (Min / Max) ~= 100MiB / 5GiB,處於ACCEPTED狀態的任務被分配到足額的內存,繼續執行。

5. 對正在運行中,即已經分配到內存後,設置更小的內存限制,原先的任務不受影響。

6. 將賬號kt94更改爲root結果同上。

總結

經過反覆測試,可以得出使用如下步驟可防止用戶濫用root賬戶(sudo 提交時,默認爲 root 賬戶)提交 spark_on_yarn 任務:

  • 新建與 root 賬戶同名的資源池:root.users.root
  • 設置 Memory(Min / Max) 的值,使其最大值略小

這樣用戶在使用root賬戶提交任務時,如果出現申請的資源過大,那麼便不能繼續執行,此時就只能找 DBA 解決了,然後就可以讓他們按規範辦事了。

最後: 根據動態資源池的原理:如果一個池的資源未被使用,它可以被佔用(preempted)並分配給其他池,即是說,如果在初始時出現幾個資源池同時出現需要額外內存的情況下,會根據它們的權重來分配內存容量:

比如,資源池 businessA 和 businessB 的權重分別爲 2 和 1,這兩個資源池中的資源都已經跑滿了,並且還有任務在排隊,此時集羣中有 30 個 Container 的空閒資源,那麼,businessA 將會額外獲得 20 個 Container 的資源,businessB 會額外獲得 10 個 Container 的資源。

所以即使沒能在初始時限制“非法”的任務被提交,通過將權重的值設置相對更小,仍然可減少對其它任務的影響。

參考鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章