cgroups,其名稱源自控制組群(control groups)的簡寫,是linux核心的一個功能,用來限制,控制與分離一個程序組群的資源(如cpu、記憶體、磁盤輸入輸出等)。最初由google的工程師提出,現在已經整合進linux核心。
cgroup的控制,統計,都是以整個cgroup來計算,即cgroup裡面程序的資源使用總合。
資源限制:組可以被設定不超過設定的記憶體限制;這也包括虛拟記憶體。
優先化:一些組可能會得到大量的cpu或磁盤輸入輸出通量。
報告:用來衡量系統确實把多少資源用到适合的目的上。
分離:為組分離命名空間,這樣一個組不會看到另一個組的程序、網絡連接配接和檔案。
控制:當機組或檢查點和重新開機動。
在cgroups中,所有和cgroups的互動都是通過cgroup的檔案系統。cgroup通過挂載層級來建立和使用者層互動的通道。
先來嘗試一下挂載。
<code>1</code>
<code>#mount -t cgroup -o 子系統 層級名 挂載點</code>
<code>2</code>
<code>#比如</code>
<code>3</code>
<code>mount</code> <code>-t cgroup -o cpu,cpuset,memory cpu_and_mem </code><code>/cgroup/cpu_and_mem</code>
<code>4</code>
<code>#這條指令把cpu,cpuset,memory附加到cpu_and_mem層級,然後挂載到 /cgroup/cpu_and_mem</code>
<code>5</code>
<code>#注意要root權限執行。</code>
<code>6</code>
<code>#執行指令後,我們會發現/cgroup/cpu_and_mem多出了很多奇怪的檔案。</code>
這些檔案後面再說,先介紹概念。
下面在介紹概念的同時,介紹這些概念在cgroup檔案系統中的表現。
說明:在cgroups中,任務就是系統的一個程序。
表現:在檔案系統中,有一個名為tasks檔案,裡儲存着程序的pid。所有移動程序的操作都是通過寫入pid到相應的tasks檔案完成。
說明:控制族群可以組織成hierarchical的形式,既一顆控制族群樹。控制族群樹上的子節點控制族群是父節點控制族群的孩子,繼承父控制族群的特定的屬性。
表現:可以看成挂載到挂載點的塊。(為什麼不說是挂載點呢?因為事實上解除安裝掉cgroup的檔案系統後,cgroup層級依然存在。這是很多cgroup錯誤的原因。)
說明:一個子系統就是一個資源控制器,比如cpu子系統就是控制cpu時間配置設定的一個控制器。子系統必須附加(attach)到一個層級上才能起作用,一個子系統附加到某個層級以後,這個層級上的所有控制族群都受到這個子系統的控制。事實上子系統比cgroup更早出現。
表現:子系統是附加到層級上的,挂載上去之後出現相應的控制檔案。
說明:控制族群就是一組按照某種标準劃分的程序。cgroups中的資源控制都是以控制族群為機關實作。一個程序可以加入到某個控制族群,也從一個程序組遷移到另一個控制族群。一個程序組的程序可以使用cgroups以控制族群為機關配置設定的資源,同時受到cgroups以控制族群為機關設定的限制。
表現:挂載點就可以認為是一個特殊的cgroup,稱之為root cgroup,在裡面建立檔案夾就對應建立一個cgroup。
解釋:mount的-o後面跟cpu,cpuset,memory等多個子系統。
注意:挂載了cpu之後,再往挂載點挂載memory不是附加多個子系統(差別層級和挂載點),這是挂載的覆寫。
解釋:當我們把cpu,cpuset附加到一個層級a,挂載後。我們不能建立cpu,memory或者是cpu或者cpu,cpuset,memory這樣的層級。
注意:有人會發現,可以再mount一個cpu,cpuse到别的目錄下。因為這沒有建立新的層級,隻是把層級再挂載到另一個目錄。可以發現,兩個挂載點中的檔案是一樣的。
解釋:準确的說是任務必須在不同的子系統。這是必然的的,因為每個子系統的實作都是在核心中,即使沒有挂載cgroup層級,它們的資料結構都存在(子系統就好像程序的各個資源次元),是以每個程序就已經和各個子系統挂鈎了。層級可以認為是子系統的展現。
反過來了解,是子系統綁定到程序,而不是程序綁定到層級。cgroup起到的是對程序分組的作用。
解釋:系統中的程序(任務)建立子程序(任務)時,該子任務自動成為其父程序所在 cgroup 的成員,它總是繼承其父任務的cgroup。可以認為是fork時,把子系統的控制結構也拷貝了一份。
每次在系統中建立新層級時,該系統中的所有任務都是那個層級的預設 cgroup(我們稱之為 root cgroup ,此cgroup在建立層級時自動建立,後面在該層級中建立的cgroup都是此cgroup的後代)的初始成員。此時它的tasks中有所有的程序pid。
可以認為這是一個預設分組,root cgroup的設定就是預設配置,裡面的子cgroup是自定義的分組,裡面的配置在建立時繼承了父cgroup的設定。建立的子cgroup中tasks為空,直到你移入程序。
注意:cgroup的繼承指的是配置的繼承,在建立新的子cgroup時,所有配置都和父cgroup相同。
我踩過的坑:我一直以為cgroup有樹狀的限制,比如cgorup a限制了記憶體最大100m,作為a的子cgroup b,限制80m,就認為,cgroup b的80m是100m的一部分。a下的程序最少用20m的記憶體。事實上,這個層級關系是有參數控制的。程序從root cgroup移入自己的子cgroup時,這個程序的統計資料就不累計到root cgroup了。
一個例外:memory子系統有一個memory.use_hierarchy,這是個布爾開關,預設為 0。此時不同層次間的資源限制和使用值都是獨立的。當設為 1 時,子控制組程序的記憶體占用也會計入父控制組,并上溯到所有 memory.use_hierarchy = 1 的祖先控制組。目前隻有memory子系統有此功能。
可以認為,對于程序來說每個cgroup都是處于同一個層次,包括root cgroup,不一樣的隻是cgroup的配置參數和劃分在這個cgroup的程序。