環境配置
cdh 5.9.0
cm 5.15.0
os centos 7.2
背景
yarn container 默認不支持對cpu進行資源隔離,一些計算密集型任務甚至可能佔滿NM節點的cpu資源,從而影響到其他任務的執行效率。
- spark streaming 出現消費延時
- 一些調度任務運行時間波動較大
例如申請的1個vcore,實際上又啓動了多線程,還有GC線程等都會造成資源使用不可控。
目標
- 限制一些計算密集型任務的CPU使用,避免多 Container 運行在同一臺機器上,cpu 爭用導致的任務運行時間不穩定,流任務消費抖動等情況
- 避免個別 Container CPU 使用過高,造成系統負載過高或者不穩定 / 影響到其他服務的穩定性(例如 DATANODE)
資源隔離
Cgroup & LinuxContainerExecutor
默認情況下,NodeManager 使用 DefaultContainerExecutor
以 NodeManager 啓動者的身份來執行啓動Container等操作,安全性低且沒有任何CPU資源隔離機制。
要達到這種目的,必須要使用 LinuxContainerExecutor
,從而以應用提交者的身份創建文件,運行/銷燬 Container。允許用戶在啓動Container後直接將CPU份額和進程ID寫入cgroup路徑的方式實現CPU資源隔離。
Cgroup 是linux kernel的一個功能,可以資源進行隔離,Yarn中現在支持對cpu/mem/io三種資源進行隔離。
cpu 資源隔離
NodeManager 通過修改 cgroup 的 cpu.cfs_period_us
,cpu.cfs_quota_us
,cpu.shares
三個文件實現對 cpu 的資源限制,還可以進一步細分爲 soft limit 和 hard limit 兩種方式。
cpu.cfs_period_us
- 時間週期,默認爲1000*1000微秒(1s),在yarn中按該時間來劃分一次cpu的時間片調度週期cpu.cfs_quota_us
- 單位時間內可用的 cpu 時間,默認無限制(-1)cpu.shares
- 用於分配cpu執行的權重,默認爲 1024
NodeManager 資源相關配置
* yarn.nodemanager.resource.cpu-vcores
nodemanager 可以分配的 vcore 數量。
* yarn.nodemanager.resource.percentage-physical-cpu-limit
nm 所有Container cpu 使用佔物理機cpu資源的比例,通過降低nm的cpu.cfs_period_us
實現。
nm 所在的物理機 core 數量爲 40,cpu limit 設置爲 90%,則 nm 上所有 container 的綜合 cpu 使用不會超過 3600%
hard limit
在 yarn.nodemanager.linux-container-executor.cgroups.strict-resource-usage
設置爲 true 時生效。通過改變cpu.cfs_quota_us
和cpu.cfs_period_us
文件控制cpu資源使用的上限。
嚴格按照任務初始分配的cpu進行限制,即使還有空閒的CPU資源也不會佔用。
core = cpu.cfs_quota_us/cpu.cfs_period_us
計算公式
- containerVCores 單個 container 申請的core
- yarnProcessors nodemanager 所在節點的物理
core * yarn.nodemanager.resource.percentage-physical-cpu-limit
nodeVcores nodemanager 設置的 VCore 數量
containerCPU = (containerVCores * yarnProcessors) / (float) nodeVCores
例如一臺4核的虛擬機,VCore 設置爲8,啓動一個vcore 爲 1 的 Container,在 yarn.nodemanager.resource.percentage-physical-cpu-limit
爲 100的情況下,使用率不會超過50%
如果將yarn.nodemanager.resource.percentage-physical-cpu-limit
設置爲90,則每個Container的cpu使用率不會超過45%
soft limit
在 yarn.nodemanager.linux-container-executor.cgroups.strict-resource-usage
設置爲 false 時生效,通過 cpu.shares
文件控制資源使用,該參數只能控制資源使用的下限。
按比例對資源進行限制,在這種模式下,允許 Container 使用額外的空閒CPU資源。
計算公式
有 VCore 分別爲 1,1,2 的三個 Container,則 cpu.shares 會被設置爲 1024 1024 2048,那麼他們可以使用的cpu時間比率爲1 : 1 : 2
啓動兩個應用,每個應用的 Container 的 VCore 都爲1,則每個executor都使用100%
啓動兩個應用,一個應用Container VCore爲1,一個應用 Container VCore爲2,前者分到的cpu 資源爲66%,後者爲132%
啓動兩個應用,一個應用Container vcore爲1,一個應用 Container vcore爲3,前者分到的cpu 資源爲50%,後者爲150%
TIPS: 由此可見,任務的可用資源會隨着不同的機器負載發生變化
兩種方式的一些對比
PCore 爲8的機器,NM VCore 設置爲6,p-limit 設置爲50。
scenario | soft limit | hard limit |
---|---|---|
啓動 4個 Container,每個 Container 的 VCore 爲1 | 100%, 100% | 66.7%, 66,7% |
啓動 2個 Container,其中一個VCore爲2,一個VCore爲1 | 200%, 100% | 133%, 66.7% |
啓動 4個 Container,其中兩個VCore爲2,兩個VCore爲1 | 133%, 66.7% | 133%, 66.7% |
總結
根據不同場景選擇限制模式
一些對比 | soft limit | hard limit |
---|---|---|
優點 | nm資源使用率高 | 資源限制更嚴格,運行時間更可控 |
缺點 | 根據機器上運行的Container資源申請情況,資源分配動態變化,可能造成運行時間不穩定 | 低負載場景下不能充分利用空閒的nm資源 |
控制方式 | 控制Container使用的cpu下限 | 控制Container使用的cpu上限 |
使用場景 | 對任務運行時間不敏感 | 集羣上運行多種類型的任務,對SLA有一定要求 |
開啓Cgroup後帶來的變化
- 計算密集型任務運行時間相比之前可能會變長,需要修改相關配置
- driver 默認使用1c,如果是 cluster 模式,driver 會運行在container中,所以也會受到限制。driver 負載比較高的任務(例如讀取了大量的分區或者task數量比較多),速度會有所下降。
- 大多數任務運行時間較之前穩定。
相關配置
參數 | 屬性 | 描述 |
---|---|---|
yarn.nodemanager.container-executor.class | org.apache.hadoop.yarn.server .nodemanager.LinuxContainerExecutor |
Yarn 是否使用 Linux Container Executor。 |
yarn.nodemanager.linux-container-executor.resources-handler.class | org.apache.hadoop.yarn.server .nodemanager.util.CgroupsLCEResourcesHandler |
YARN 是否根據容器創建 cgroup,從而隔離容器的 CPU 使用情況 |
yarn.nodemanager.linux-container-executor.cgroups.hierarchy | /hadoop-yarn | yarn 使用的 cgroup 組,默認爲/hadoop-yarn,一般不作修改 |
yarn.nodemanager.linux-container-executor.cgroups.mount | true | 是否自動掛載cgroup |
yarn.nodemanager.linux-container-executor.cgroups.mount-path | /sys/fs/cgroup | cgroup 掛載目錄,centos7 爲/sys/fs/cgroup,centos6 爲 /cgroup |
yarn.nodemanager.linux-container-executor.group | yarn | 容器執行組,一般無需設置 |
yarn.nodemanager.resource.percentage-physical-cpu-limit | 90 | 配置nodemanager使用多少物理cpu資源,比如24核服務器配置90的話,只能使用21.6核 |
yarn.nodemanager.linux-container-executor.cgroups.strict-resource-usage | true | 是否啓用嚴格資源限制,按任務申請的CPU數量控制 / 按core的比率限制 |
yarn.nodemanager.linux-container-executor.nonsecure-mode.local-user | nobody | 使用 Linux-container-executor 時,運行容器的 UNIX 用戶,一般不用更改 |
相關代碼
CgroupsLCEResourcesHandler.setupLimits
public void setupLimits(ContainerId containerId,
Resource containerResource) throws IOException {
String containerName = containerId.toString();
if (isCpuWeightEnabled()) {
int containerVCores = containerResource.getVirtualCores();
createCgroup(CONTROLLER_CPU, containerName);
int cpuShares = CPU_DEFAULT_WEIGHT * containerVCores;
// absolute minimum of 10 shares for zero CPU containers
cpuShares = Math.max(cpuShares, 10);
updateCgroup(CONTROLLER_CPU, containerName, "shares",
String.valueOf(cpuShares));
if (strictResourceUsageMode) {
int nodeVCores =
conf.getInt(YarnConfiguration.NM_VCORES,
YarnConfiguration.DEFAULT_NM_VCORES);
if (nodeVCores != containerVCores) {
// yarnProcessors 爲物理機總線程數 * cpu_limit
float containerCPU =
(containerVCores * yarnProcessors) / (float) nodeVCores;
int[] limits = getOverallLimits(containerCPU);
updateCgroup(CONTROLLER_CPU, containerName, CPU_PERIOD_US,
String.valueOf(limits[0]));
updateCgroup(CONTROLLER_CPU, containerName, CPU_QUOTA_US,
String.valueOf(limits[1]));
}
}
}
}