本文轉載於:http://edsionte.com/techblog/archives/4314
Cgroup(Control Groups)是這樣一種機制:它以分組的形式對進程使用系統資源的行爲進行管理和控制。也就是說,用戶通過cgroup對所有進程進行分組,再對該分組整體進行資源的分配和控制。
1 Cgroup的結構
cgroup中的每個分組稱爲進程組,它包含多個進程。最初情況下,系統內的所有進程形成一個進程組(根進程組),根據系統對資源的需求,這個根進程組將被進一步細分爲子進程組,子進程組內的進程是根進程組內進程的子集。而這些子進程組很有可能繼續被進一步細分,最終,系統內所有的進程組形成一顆具有層次等級(hierarchy)關係的進程組樹。如下圖:
由於進程組可以被進一步劃分,因此一個進程可能處於多個進程組中,但這些進程組必然不處於同一層級中。
另外,如果某個進程組內的進程創建了子進程,那麼該子進程默認與父進程處於同一進程組中。也就是說,cgroup對改進程組的資源控制同樣作用於子進程。
2 subsystem
cgroup是一種對進程資源管理和控制的統一框架,它提供的是一種機制(mechanism),而具體的策略(policy)是通過子系統(subsystem)來完成的,子系統是cgroup對進程組進行資源控制的具體行爲。機制和策略是Linux操作系統中一種經典的設計思想,所謂機制就是“我要提供哪種功能”,而策略則是“我要怎樣來實現這種功能”。
cgroup中每個子系統都代表一種類型的資源,具體如下:
1) cpu子系統:該子系統爲每個進程組設置一個使用CPU的權重值,以此來管理進程對cpu的訪問。
2) cpuset子系統:對於多核cpu,該子系統可以設置進程組只能在指定的核上運行,並且還可以設置進程組在指定的內存節點上申請內存。
3) cpuacct子系統:該子系統只用於生成當前進程組內的進程對cpu的使用報告。
4) memory子系統:該子系統提供了以頁面爲單位對內存的訪問,比如對進程組設置內存使用上限等,同時可以生成內存資源報告
5) blkio子系統:該子系統用於限制每個塊設備的輸入輸出。首先,與CPU子系統類似,該系統通過爲每個進程組設置權重來控制塊設備對其的I/O時間;其次,該子系統也可以限制進程組的I/O帶寬以及IOPS。
6) devices子系統:通過該子系統可以限制進程組對設備的訪問,即該允許或禁止進程組對某設備的訪問。
7) freezer子系統:該子系統可以使得進程組中的所有進程掛起。
8) net-cls子系統:該子系統提供對網絡帶寬的訪問限制,比如對發送帶寬和接收帶寬進程限制。
如果要實現子系統對所屬進程組的資源控制,那麼就要實現該子系統對應的鉤子函數。這個關係與虛擬文件系統類似,VFS提供統一的用戶接口,而具體的文件操作則通過文件系統(比如ext3)對鉤子函數的實現。具體關係如下圖:
由圖可以看出,cgroup在用戶態提供統一的用戶接口,而每個子系統對資源的控制功能則通過其鉤子函數實現。這樣使得cgroup在上層是一個統一的框架,而下層則可以實現多種資源的控制。每個子系統的鉤子函數如下:
1 |
struct
cgroup_subsys { |
2 |
struct
cgroup_subsys_state *(*css_alloc)( struct
cgroup *cgrp); |
3 |
int
(*css_online)( struct
cgroup *cgrp); |
4 |
void
(*css_offline)( struct
cgroup *cgrp); |
5 |
void
(*css_free)( struct
cgroup *cgrp); |
6 |
7 |
int
(*can_attach)( struct
cgroup *cgrp, struct
cgroup_taskset *tset); |
8 |
void
(*cancel_attach)( struct
cgroup *cgrp, struct
cgroup_taskset *tset); |
9 |
void
(*attach)( struct
cgroup *cgrp, struct
cgroup_taskset *tset); |
10 |
void
(*fork)( struct
task_struct *task); |
11 |
void
(* exit )( struct
cgroup *cgrp, struct
cgroup *old_cgrp, |
12 |
struct
task_struct *task); |
13 |
void
(*bind)( struct
cgroup *root); |
14 |
…… …… |
15 |
} |
3 cgroup文件系統
cgroup在Linux內核中是以文件系統的形式存在的,不過cgroup對應的這種文件系統與proc文件系統類似,都是隻存在於內存中的“虛擬”文件系統。既然如此,就可以通過mount命令創建一個cgroup實例。
1 |
$ sudo mount -t cgroup -o memory memory_cgroup /dev/cgroup/ |
即在/dev/cgroup/下創建了一個memory子系統。接下來就可以通過:
1 |
$ cat /proc/filesystems | grep cgroup |
可看到系統有了cgroup類型的文件系統。
當創建了一個cgroup實例後,對應的掛載點下會有一些文件,這些文件是用戶與cgroup進行交互的接口。由於cgroup位於VFS層之下,因此用戶可以通過統一的文件操作接口去讀取或設置子系統的參數,當然也可以直接使用echo或者cat等命令。