簡介
在大資料迅速發展的今天, 很大一部分支援來自於底層技術的不斷發展, 其中非常重要的一點就是系統資源的管理和控制, 大資料平臺的核心就是對資源的調度管理, 在調度和管理之後如何對這些資源進行控制便成了另一個重要的問題。 大資料系統中使用者成千上萬的作業進程跑在集群中, 如果不能對這些進程的資源進行控制, 那麼大資料平臺將變得舉步維艱, 整個集群便會隨時崩潰。 同時, 大資料作業的調度也是基於資源的配額進行分配, 大資料的作業本身就承載了資源配額的屬性,
本文針對大資料平臺中資源控制這個層面來詳細介紹資源控制在不同作業系統上的具體技術實現, 以及大資料平臺和資源控制的集成。
資源控制使用的系統功能
cgroup簡介
cgroup是Linux內核的一部分, cgroup可以為一組進程定義組群分配資源, 這個組群分配資源可以包含CPU時間, 記憶體, 網路頻寬, 並且定義的這些資源配置可以動態修改。 cgroup以一種層級結構(hierarchical)聚合和管理進程, 將所有任務進程以資料夾的形式組成一個控制族群樹, 子控制組自動繼承父節點的特定屬性,
cgroup提供一些subsystem作為控制族群樹的根節點, 所有的任務進程都以這些子系統為入口按樹狀結構設置資源配額。 Red Hat Linux 7.3 提供 12 個 cgroup 子系統, 根據名稱和功能列出如下。
cgroup各子系統功能
![](/images/lazyload.gif)
可通過以下命令查看作業系統支援的cgroup子系統,
cgroup的操作沒有提供系統API調用或者命令列, 而是直接訪問cgroup mount的這個檔案系統, 舉個例子描述下cgroup介面的使用方式。
1. 創建一個目錄用於指定需要控制的作業進程, 創建之後系統在會每一級自動生成所有的設定檔, 可以將該目錄認為是一個資源控制組。
2. 添加需要的進程到該資源控制組, 可以添加多個進程ID
3. 設置該資源控制組的實體記憶體使用配額
如果不進行設置, 預設情況下, 繼承根目錄的記憶體配置, 即系統記憶體。
下面介紹下大資料系統中常用的配額設置。
記憶體:實體記憶體的設置檔為memory子系統下的memory.limit_in_bytes, 虛擬記憶體為memory.memsw.limit_in_bytes。 如果同時設置這兩個參數,
CPU:對CPU的配額控制是通過CPU子系統下的cpu.cfs_period_us和cpu.cfs_quota_us兩個參數控制。 cpu.cfs_period_us表示重新分配CPU時間的週期, 默認為 100000, 即百毫秒。 cpu.cfs_quota_us就是在這期間內可使用的 cpu 時間, 默認 -1, 即無限制。 所以預設情況下CPU的使用為100%。 如果需要將CPU的使用設置為50%, 可以將 cpu.cfs_quota_us設為 50000, cpu.cfs_period_us保持100000, 表示每隔100毫秒分配CPU時間, 持續使用50毫秒。 對CPU的限制不像記憶體, 超過配額後再申請的話就會觸發OOM kill掉進程,
JobObjects簡介
Windows平臺也有對應的內核對象用來控制作業對系統資源的訪問, 而且控制的範圍比Linux廣, 包括剪切板, 關閉Windows的許可權, 窗口許可權等。 不同於Linux, Windows通過系統API來實現對作業物件的訪問。
Windows JobObjects支持的列表
Windows上使用內核作業物件的流程大概如下:
創建內核作業對象:調用::CreateJobObject創建一個內核對象, 剛創建的物件沒有和進程關聯。 把限制屬性設置到作業物件:調用:: SetInformationJobObject可以設置如上清單中的限制屬性到該作業物件。 將進程加入到作業物件:調用:: AssignProcessToJobObject將進程加入到作業中, 如果該進程產生子進程, 那麼該子進程會自動成為作業的一部分。 關閉作業對象:調用:: CloseHandle關閉作業對象的控制碼。需要注意以下幾點:
一個進程屬於一個作業物件之後,不能再assign給另一個作業對象。在Windows開啟UAC的系統中,沒有提示許可權的進程會被加入到一個預設的相容性系統作業物件中,所以必須使用CREATE_BREAKAWAY_FROM_JOB參數創建進程使該進程脫離預設的作業物件。新啟動的進程最好使用CREATE_SUSPEND參數這樣可以在進程啟動之前加入到作業物件中,防止起啟動的新的子進程逃離作業物件。Windows對於記憶體的管理與Linux不同,Windows上的實體記憶體指的是WorkingSet,虛擬記憶體指的是committed memory,在Windows工作管理員中看的話實體記憶體指的是“工作設置(記憶體)”,虛擬記憶體指的是“提交大小”。CPU通過CpuRate設置,CpuRate的含義是執行緒在每10000個處理器調度週期內被調度的週期數,比如需要限制到20%,就設置CpuRate為2000。
下面直接以C++代碼為例來說明如果創建和管理作業物件,同時包含如何與ACE進程物件如何集成。
![](/images/lazyload.gif)
Docker容器資源控制
目前在Linux生態圈,用Docker發佈和運行程式基本已經成為一個標準,同時用Docker管理本地私有雲也越來越流行,尤其對於用Kubernetes管理的容器雲,如何限制容器資源變得非常重要。
在RedHat上,Docker擁有自己的cgroup控制目錄,位於各個子系統下的system.slice的資料夾裡面。當我們啟動一個docker容器之後,就會產生這個容器ID開頭的一個子目錄,用來配置這個容器裡面的所有進程對系統資源的使用。
其中task目錄中存放的為容器中進程的PID,以我們這個示例來說,我們在容器中啟動了 /bin/sh 進程,這個進程ID為2730。
雲計算中Docker容器的資源收集
目前通過Docker容器部署大資料平臺也比較流行,但是大資料平臺需要獲取每個節點運行環境的資源配額,對於已經運行在Docker容器裡面的進程,如何判斷自己擁有多少系統資源也可以通過cgroup檔案系統獲取。但是Docker容器裡面看到的cgroup的檔目錄和宿主機不同,docker容器裡面沒有system.slice資料夾,直接以/sys/fs/cgroup/開頭,可以通過命令查看。所以可以通過這個目錄下的memory.limit_in_bytes獲取容器自身的實體記憶體配額。對於容器中CPU core數目的獲取,可以通過這個公式獲取到近似的core數:min(1, (int)ceil(cpu.cfs_quota_us/cpu.cfs_period_us))。
用Kubernetes部署的容器平臺需要提前定義資源配額,否則容器可以使用到宿主機的所有資源,資源配額在YAML檔的resources中定義:
![](/images/lazyload.gif)
YARN容器管理
作為容器管理的平臺,Kubernetes主要用來在容器中部署分散式應用程式,YARN作為一個資源管理平臺也支持容器的管理,主要用來以容器的方式運行大資料作業。像Spark將YARN作為資源管理器運行Spark job。
YARN支援對現有容器大小的調整(cgroup和jobobjects都支援修改資源配額),當用戶從YARN申請了一些固定大小的容器,想改變容器資源配額的大小的時候不需要釋放掉這些容器重新申請,YARN支援動態改變已經分配的容器的大小。
![](/images/lazyload.gif)
結束語
隨著大資料和雲計算技術的發展,資源控制和管理作為底層技術已經非常成熟,掌握這些技術便可以在大資料處理中遊刃有餘。
一個進程屬於一個作業物件之後,不能再assign給另一個作業對象。在Windows開啟UAC的系統中,沒有提示許可權的進程會被加入到一個預設的相容性系統作業物件中,所以必須使用CREATE_BREAKAWAY_FROM_JOB參數創建進程使該進程脫離預設的作業物件。新啟動的進程最好使用CREATE_SUSPEND參數這樣可以在進程啟動之前加入到作業物件中,防止起啟動的新的子進程逃離作業物件。Windows對於記憶體的管理與Linux不同,Windows上的實體記憶體指的是WorkingSet,虛擬記憶體指的是committed memory,在Windows工作管理員中看的話實體記憶體指的是“工作設置(記憶體)”,虛擬記憶體指的是“提交大小”。CPU通過CpuRate設置,CpuRate的含義是執行緒在每10000個處理器調度週期內被調度的週期數,比如需要限制到20%,就設置CpuRate為2000。
下面直接以C++代碼為例來說明如果創建和管理作業物件,同時包含如何與ACE進程物件如何集成。
![](/images/lazyload.gif)
Docker容器資源控制
目前在Linux生態圈,用Docker發佈和運行程式基本已經成為一個標準,同時用Docker管理本地私有雲也越來越流行,尤其對於用Kubernetes管理的容器雲,如何限制容器資源變得非常重要。
在RedHat上,Docker擁有自己的cgroup控制目錄,位於各個子系統下的system.slice的資料夾裡面。當我們啟動一個docker容器之後,就會產生這個容器ID開頭的一個子目錄,用來配置這個容器裡面的所有進程對系統資源的使用。
其中task目錄中存放的為容器中進程的PID,以我們這個示例來說,我們在容器中啟動了 /bin/sh 進程,這個進程ID為2730。
雲計算中Docker容器的資源收集
目前通過Docker容器部署大資料平臺也比較流行,但是大資料平臺需要獲取每個節點運行環境的資源配額,對於已經運行在Docker容器裡面的進程,如何判斷自己擁有多少系統資源也可以通過cgroup檔案系統獲取。但是Docker容器裡面看到的cgroup的檔目錄和宿主機不同,docker容器裡面沒有system.slice資料夾,直接以/sys/fs/cgroup/開頭,可以通過命令查看。所以可以通過這個目錄下的memory.limit_in_bytes獲取容器自身的實體記憶體配額。對於容器中CPU core數目的獲取,可以通過這個公式獲取到近似的core數:min(1, (int)ceil(cpu.cfs_quota_us/cpu.cfs_period_us))。
用Kubernetes部署的容器平臺需要提前定義資源配額,否則容器可以使用到宿主機的所有資源,資源配額在YAML檔的resources中定義:
![](/images/lazyload.gif)
YARN容器管理
作為容器管理的平臺,Kubernetes主要用來在容器中部署分散式應用程式,YARN作為一個資源管理平臺也支持容器的管理,主要用來以容器的方式運行大資料作業。像Spark將YARN作為資源管理器運行Spark job。
YARN支援對現有容器大小的調整(cgroup和jobobjects都支援修改資源配額),當用戶從YARN申請了一些固定大小的容器,想改變容器資源配額的大小的時候不需要釋放掉這些容器重新申請,YARN支援動態改變已經分配的容器的大小。
![](/images/lazyload.gif)
結束語
隨著大資料和雲計算技術的發展,資源控制和管理作為底層技術已經非常成熟,掌握這些技術便可以在大資料處理中遊刃有餘。