需求背景
講道理,用戶在提交 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 中,配置資源池的容量大小,界面示例如下:
3. 反覆提交執行與更改配置,並觀察結果
測試結果
注 1:以下測試僅測試提交時申請的 AM 內存大小與配置的最大內存大小關係,暫未考慮權重(Weight)的影響,後面總結會提到權重。
注 2:--executor-memory
是指定的執行內存,但是因爲存在額外的管理開銷,所以實際的AM 使用內存
會大於--executor-memory
指定的值,而配置的內存限制的是AM 的使用內存
,所以下方比較的是AM memory
和max 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 的資源。
所以即使沒能在初始時限制“非法”的任務被提交,通過將權重的值設置相對更小,仍然可減少對其它任務的影響。