Cgroups 是 Linux 系統(tǒng)內(nèi)核提供的一種機(jī)制,這種機(jī)制可以根據(jù)需求將一些列系統(tǒng)任務(wù)機(jī)器子任務(wù)整合或分離到按資源劃分登記的不同組內(nèi),從而為系統(tǒng)資源管理提供一個(gè)的框架。簡單地說,cgroups 可以限制、記錄任務(wù)組所使用的物理組員(比如 CPU、Memory、IO等),為容器實(shí)現(xiàn)虛擬化提供了基本保證,是構(gòu)建 Docker 等一些列虛擬化管理工具的基石。今天我們就來詳細(xì)介紹一下 cgroups 相關(guān)的內(nèi)容。
1. 為什么要了解 Cgroups
從2013年開源的 Docker 推出、2014年開源的 Kubernetes 出現(xiàn),到現(xiàn)在的云原生技術(shù)與生態(tài)的全面普及與火熱化,容器技術(shù)已經(jīng)逐步成為主流的基礎(chǔ)云原生技術(shù)之一。使用容器技術(shù),可以很好地實(shí)現(xiàn)資源層面上的限制和隔離,這都依賴于 Linux 系統(tǒng)內(nèi)核所提供的Cgroups和 Namespace技術(shù)。
Cgroups 主要用來管理資源的分配、限制;Namespace 主要用來封裝抽象、限制、隔離資源,使命名空間內(nèi)的進(jìn)程擁有它們自己的全局資源。
Linux內(nèi)核提供的 Cgroups 和 Namespace 技術(shù),為容器實(shí)現(xiàn)虛擬化提供了基本保證,是構(gòu)建 Docker 等一些列虛擬化管理工具的基石。下面我們就來詳細(xì)介紹一下 Cgroups 相關(guān)的內(nèi)容。
2. Cgroups簡介
Cgroups 是 control groups 的縮寫,是 Linux 內(nèi)核提供的一種可以限制、記錄、隔離進(jìn)程組(process groups)所使用的物理資源(如 CPU、Memory、IO 等等)的機(jī)制。
通過使用 Cgroups,系統(tǒng)管理員在分配、排序、拒絕、管理和監(jiān)控系統(tǒng)資源等方面,可以進(jìn)行精細(xì)化控制。硬件資源可以在應(yīng)用程序和用戶間智能分配,從而增加整體效率。最初由 google 的工程師提出,后來被整合進(jìn) Linux 內(nèi)核。也是目前輕量級虛擬化技術(shù) XC(Linux Container)的基礎(chǔ)之一。
Cgroups 和 Namespace 類似,也是將進(jìn)程進(jìn)行分組,但它的目的和 Namespace 不一 樣,Namespace 是為了隔離進(jìn)程組之間的資源,而 Cgroups 是為了對一組進(jìn)程進(jìn)行統(tǒng)一的資源監(jiān)控和限制。
Cgroups 分 v1 和 v2 兩個(gè)版本,v1 實(shí)現(xiàn)較早,功能比較多,但是由于它里面的功能都是零零散散的實(shí)現(xiàn)的,所以規(guī)劃的不是很好,導(dǎo)致了一些使用和維護(hù)上的不便,v2 的出現(xiàn) 就是為了解決 v1 中這方面的問題,在最新的 4.5 內(nèi)核中,Cgroups v2 聲稱已經(jīng)可以用于生產(chǎn)環(huán)境了,但它所支持的功能還很有限,隨著 v2 一起引入內(nèi)核的還有 Cgroups、Namespace,v1 和 v2 可以混合使用,但是這樣會(huì)更復(fù)雜,所以一般沒人會(huì)這樣用。
3. 什么是 Cgroups?
Cgroups 是 Linux 下的一種將進(jìn)程按組進(jìn)行管理的機(jī)制,在用戶層看來,Cgroups 技術(shù)就是把系統(tǒng)中的所有進(jìn)程組織成一顆一顆獨(dú)立的樹,每棵樹都包含系統(tǒng)的所有進(jìn)程,樹的每個(gè)節(jié)點(diǎn)是一個(gè)進(jìn)程組,而每顆樹又和一個(gè)或者多個(gè) subsystem 關(guān)聯(lián),樹的作用是將進(jìn)程分組,而 subsystem 的作用就是對這些組進(jìn)行操作,Cgroups 的主體架構(gòu)提如下:
Cgroups 主要包括下面兩部分:
subsystem: 一個(gè) subsystem 就是一個(gè)內(nèi)核模塊,他被關(guān)聯(lián)到一顆 cgroup 樹之后, 就會(huì)在樹的每個(gè)節(jié)點(diǎn)(進(jìn)程組)上做具體的操作。subsystem 經(jīng)常被稱作 resource controller,因?yàn)樗饕挥脕碚{(diào)度或者限制每個(gè)進(jìn)程組的資源,但是這個(gè)說法不完全準(zhǔn) 確,因?yàn)橛袝r(shí)我們將進(jìn)程分組只是為了做一些監(jiān)控,觀察一下他們的狀態(tài),比如 perf_event subsystem。到目前為止,Linux 支持 12 種 subsystem,比如限制 CPU 的使 用時(shí)間,限制使用的內(nèi)存,統(tǒng)計(jì) CPU 的使用情況,凍結(jié)和恢復(fù)一組進(jìn)程等,后續(xù)會(huì)對它們一一進(jìn)行介紹。
hierarchy: 一個(gè) hierarchy 可以理解為一棵 cgroup 樹,樹的每個(gè)節(jié)點(diǎn)就是一個(gè)進(jìn)程 組,每棵樹都會(huì)與零到多個(gè) subsystem 關(guān)聯(lián)。在一顆樹里面,會(huì)包含 Linux 系統(tǒng)中的所有 進(jìn)程,但每個(gè)進(jìn)程只能屬于一個(gè)節(jié)點(diǎn)(進(jìn)程組)。系統(tǒng)中可以有很多顆 cgroup 樹,每棵樹 都和不同的 subsystem 關(guān)聯(lián),一個(gè)進(jìn)程可以屬于多顆樹,即一個(gè)進(jìn)程可以屬于多個(gè)進(jìn)程 組,只是這些進(jìn)程組和不同的 subsystem 關(guān)聯(lián)。
目前 Linux 支持 12 種 subsystem,如果不考慮不與任何 subsystem 關(guān)聯(lián)的情況(systemd 就屬于這種情況),Linux 里面最多可以建 12 顆 cgroup 樹,每棵樹關(guān)聯(lián)一個(gè) subsystem,當(dāng)然也可以只建一棵樹,然后讓這 棵樹關(guān)聯(lián)所有的 subsystem。當(dāng)一顆 cgroup 樹不和任何 subsystem 關(guān)聯(lián)的時(shí)候,意味著這棵樹只是將進(jìn)程進(jìn)行分組,至于要在分組的基礎(chǔ)上做些什么,將由應(yīng)用程序自己決定, systemd 就是一個(gè)這樣的例子。
4. 為什么需要 Cgroups?
在 Linux 里,一直以來就有對進(jìn)程進(jìn)行分組的概念和需求,比如 session group, progress group 等,后來隨著人們對這方面的需求越來越多,比如需要追蹤一組進(jìn)程的內(nèi)存和 IO 使用情況等,于是出現(xiàn)了 cgroup,用來統(tǒng)一將進(jìn)程進(jìn)行分組,并在分組的基礎(chǔ)上對進(jìn)程進(jìn)行監(jiān)控和資源控制管理等。
舉個(gè)例子,Linux 系統(tǒng)中安裝了殺毒軟件 ESET 或者 ClamAV,殺毒時(shí)占用系統(tǒng)資源過高,影響系統(tǒng)承載業(yè)務(wù)運(yùn)行,怎么辦?單個(gè)虛擬機(jī)進(jìn)程或者 docker 進(jìn)程使用過高的資源,怎么辦?單個(gè)Java進(jìn)行占用系統(tǒng)過多的內(nèi)存的資源,怎么辦?
cgroup 就是能夠控制并解決上述問題的工具,cgroup 在 linux 內(nèi)核實(shí)現(xiàn)、用于控制 linux 系統(tǒng)資源。
5. Cgroups 是如何實(shí)現(xiàn)的?
在 CentOS 7 系統(tǒng)中(包括 Red Hat Enterprise Linux 7),通過將 cgroup 層級系統(tǒng)與 systemd 單位樹捆綁,可以把資源管理設(shè)置從進(jìn)程級別移至應(yīng)用程序級別。默認(rèn)情況下 systemd 會(huì)自動(dòng)創(chuàng)建 slice、scope 和 service 單位的層級(具體的意思稍后再解釋),來為 cgroup 樹提供統(tǒng)一結(jié)構(gòu)。
可以通過 systemctl 命令創(chuàng)建自定義 slice 進(jìn)一步修改此結(jié)構(gòu)。如果我們將系統(tǒng)的資源看成一塊餡餅,那么所有資源默認(rèn)會(huì)被劃分為 3 個(gè) cgroup:System, User 和 Machine。每一個(gè) cgroup 都是一個(gè) slice,每個(gè) slice 都可以有自己的子 slice,如下圖所示:
下面我們以 CPU 資源為例,來解釋一下上圖中出現(xiàn)的一些關(guān)鍵詞。如上圖所示,系統(tǒng)默認(rèn)創(chuàng)建了 3 個(gè)頂級 slice(System, User 和 Machine),每個(gè) slice 都會(huì)獲得相同的 CPU 使用時(shí)間(僅在 CPU 繁忙時(shí)生效),如果 user.slice 想獲得 100% 的 CPU 使用時(shí)間,而此時(shí) CPU 比較空閑,那么 user.slice 就能夠如愿以償。這三種頂級 slice 的含義如下:
1)system.slice:所有系統(tǒng) service 的默認(rèn)位置。
2)user.slice:所有用戶會(huì)話的默認(rèn)位置。每個(gè)用戶會(huì)話都會(huì)在該 slice 下面創(chuàng)建一個(gè)子 slice,如果同一個(gè)用戶多次登錄該系統(tǒng),仍然會(huì)使用相同的子 slice。
3)machine.slice:所有虛擬機(jī)和 Linux 容器的默認(rèn)位置 控制 CPU 資源使用的其中一種方法是 shares。shares 用來設(shè)置 CPU 的相對值(你可以理解為權(quán) 重),并且是針對所有的 CPU(內(nèi)核),默認(rèn)值是 1024。因此在上圖中,httpd, sshd, crond 和 gdm 的 CPU shares 均為 1024,System, User 和 Machine 的 CPU shares 也是 1024。
假設(shè)該系統(tǒng)上運(yùn)行了 4 個(gè) service,登錄了兩個(gè)用戶,還運(yùn)行了一個(gè)虛擬機(jī)。同時(shí)假設(shè) 每個(gè)進(jìn)程都要求使用盡可能多的 CPU 資源(每個(gè)進(jìn)程都很繁忙),則:
1)system.slice 會(huì)獲得 33.333% 的 CPU 使用時(shí)間,其中每個(gè) service 都會(huì)從 system.slice 分配的 資源中獲得 1/4 的 CPU 使用時(shí)間,即 8.25% 的 CPU 使用時(shí)間。
2)user.slice 會(huì)獲得 33.333% 的 CPU 使用時(shí)間,其中每個(gè)登錄的用戶都會(huì)獲得 16.5% 的 CPU 使 用時(shí)間。假設(shè)有兩個(gè)用戶:tom 和 jack,如果 tom 注銷登錄或者殺死該用戶會(huì)話下的所有進(jìn)程, jack 就能夠使用 33.333% 的 CPU 使用時(shí)間。
3)machine.slice 會(huì)獲得 33.333% 的 CPU 使用時(shí)間,如果虛擬機(jī)被關(guān)閉或處于 idle 狀態(tài),那么 system.slice 和 user.slice 就會(huì)從這 33.333% 的 CPU 資源里分別獲得 50% 的 CPU 資源,然后 均分給它們的子 slice。
6. Cgroups 的作用
Cgroups 最初的目標(biāo)是為資源管理提供的一個(gè)統(tǒng)一的框架,既整合現(xiàn)有的 cpuset 等子系統(tǒng),也為未來開發(fā)新的子系統(tǒng)提供接口。現(xiàn)在的 cgroups 適用于多種應(yīng)用場景,從單個(gè)進(jìn)程的資源控制,到實(shí)現(xiàn)操作系統(tǒng)層次的虛擬化(OS Level Virtualization),框架圖如下:
Cgroups提供了以下功能:
1)限制進(jìn)程組可以使用的資源數(shù)量(Resource limiting )。比如:memory子系統(tǒng)可以為進(jìn)程 組設(shè)定一個(gè)memory使用上限,一旦進(jìn)程組使用的內(nèi)存達(dá)到限額再申請內(nèi)存,就會(huì)出發(fā) OOM(out of memory)。
2)進(jìn)程組的優(yōu)先級控制(Prioritization )。比如:可以使用cpu子系統(tǒng)為某個(gè)進(jìn)程組分配特定 cpu share。
3)記錄進(jìn)程組使用的資源數(shù)量(Accounting )。比如:可以使用cpuacct子系統(tǒng)記錄某個(gè)進(jìn)程 組使用的cpu時(shí)間。
4)進(jìn)程組隔離(Isolation)。比如:使用ns子系統(tǒng)可以使不同的進(jìn)程組使用不同的 namespace,以達(dá)到隔離的目的,不同的進(jìn)程組有各自的進(jìn)程、網(wǎng)絡(luò)、文件系統(tǒng)掛載空間。
5)進(jìn)程組控制(Control)。比如:使用freezer子系統(tǒng)可以將進(jìn)程組掛起和恢復(fù)。
7. Cgroups 相關(guān)概念及相互關(guān)系
7.1 相關(guān)概念
1)任務(wù)(task):在 cgroups 中,任務(wù)就是系統(tǒng)的一個(gè)進(jìn)程。
2)控制族群(control group):控制族群就是一組按照某種標(biāo)準(zhǔn)劃分的進(jìn)程。Cgroups 中的資源控制都是以控制族群為單位實(shí)現(xiàn)。一個(gè)進(jìn)程可以加入到某個(gè)控制族群,也從一個(gè)進(jìn)程組遷移到另 一個(gè)控制族群。一個(gè)進(jìn)程組的進(jìn)程可以使用 cgroups 以控制族群為單位分配的資源,同時(shí)受到 cgroups 以控制族群為單位設(shè)定的限制。
3)層級(hierarchy):控制族群可以組織成 hierarchical 的形式,既一顆控制族群樹??刂谱?群樹上的子節(jié)點(diǎn)控制族群是父節(jié)點(diǎn)控制族群的孩子,繼承父控制族群的特定的屬性。
4)子系統(tǒng)(subsystem):一個(gè)子系統(tǒng)就是一個(gè)資源控制器,比如 cpu 子系統(tǒng)就是控制 cpu 時(shí)間分配的一個(gè)控制器。子系統(tǒng)必須附加(attach)到一個(gè)層級上才能起作用,一個(gè)子系統(tǒng)附加到某個(gè) 層級以后,這個(gè)層級上的所有控制族群都受到這個(gè)子系統(tǒng)的控制。
7.2 相互關(guān)系
1)每次在系統(tǒng)中創(chuàng)建新層級時(shí),該系統(tǒng)中的所有任務(wù)都是那個(gè)層級的默認(rèn) cgroup(我們稱之為 root cgroup ,此 cgroup 在創(chuàng)建層級時(shí)自動(dòng)創(chuàng)建,后面在該層級中創(chuàng)建的 cgroup 都是此 cgroup 的后代)的初始成員。
2)一個(gè)子系統(tǒng)最多只能附加到一個(gè)層級。
3)一個(gè)層級可以附加多個(gè)子系統(tǒng)
4)一個(gè)任務(wù)可以是多個(gè) cgroup 的成員,但是這些 cgroup 必須在不同的層級。
5)系統(tǒng)中的進(jìn)程(任務(wù))創(chuàng)建子進(jìn)程(任務(wù))時(shí),該子任務(wù)自動(dòng)成為其父進(jìn)程所在 cgroup 的成員。然后可根據(jù)需要將該子任務(wù)移動(dòng)到不同的 cgroup 中,但開始時(shí)它總是繼承其父任務(wù)的 cgroup。
8. Cgroups 子系統(tǒng)介紹
可以看到,在 /sys/fs/cgroup 下面有很多 cpu、memory 這樣的子目錄,也就稱為子系統(tǒng) subsystem:
它是一組資源控制模塊,一般包含如下幾項(xiàng):
1)net_cls:將 cgroup 中進(jìn)程產(chǎn)生的網(wǎng)絡(luò)包分類,以便 Linux 的 tc(traffic controller) 可以根據(jù)分類區(qū)分出來自某個(gè) cgroup 的包并做限流或監(jiān)控。這個(gè)子系統(tǒng)使用等級識別符(classid)標(biāo)記網(wǎng)絡(luò)數(shù)據(jù)包,可允許 Linux 流量控制程序 (tc)識別從具體 cgroup 中生成的數(shù)據(jù)包。
2)net_prio:設(shè)置 cgroup 中進(jìn)程產(chǎn)生的網(wǎng)絡(luò)流量的優(yōu)先級。
3)memory:控制 cgroup 中進(jìn)程的內(nèi)存占用。
4)cpuset:在多核機(jī)器上設(shè)置 cgroup 中進(jìn)程可以使用的 cpu 和內(nèi)存。這個(gè)子系統(tǒng)為 cgroup 中的任務(wù)分配獨(dú)立 CPU(在多核系統(tǒng))和內(nèi)存節(jié)點(diǎn)。
5)freezer:掛起(suspend)和恢復(fù)(resume) cgroup 中的進(jìn)程。這個(gè)子系統(tǒng)掛起或者恢復(fù) cgroup 中的任務(wù)。
6)blkio:設(shè)置對塊設(shè)備(如硬盤)輸入輸出的訪問控制。這個(gè)子系統(tǒng)為塊設(shè)備設(shè)定輸入/輸出限制,比如物理設(shè)備(磁盤,固態(tài)硬盤,USB 等等)。
7)cpu:設(shè)置 cgroup 中進(jìn)程的 CPU 占用。這個(gè)子系統(tǒng)使用調(diào)度程序提供對 CPU 的 cgroup 任務(wù)訪問。
8)cpuacct:統(tǒng)計(jì) cgroup 中進(jìn)程的 CPU 占用。這個(gè)子系統(tǒng)自動(dòng)生成 cgroup 中任務(wù)所使用的 CPU 報(bào)告。
9)devices:控制 cgroup 中進(jìn)程對設(shè)備的訪問 16 這個(gè)子系統(tǒng)可允許或者拒絕 cgroup 中的任務(wù)訪問設(shè)備。
8.1 如何查看當(dāng)前系統(tǒng)支持哪些 subsystem?
可以通過查看 /proc/cgroups(since Linux 2.6.24)知道當(dāng)前系統(tǒng)支持哪些 subsystem,下面 是一個(gè)例子:
?
#subsys_name?hierarchy?num_cgroups?enabled? cpuset?11?1?1? cpu?3?64?1? cpuacct?3?64?1? blkio?8?64?1? memory?9?104?1? devices?5?64?1? freezer?10?4?1? net_cls?6?1?1? perf_event?7?1?1? net_prio?6?1?1? hugetlb?4?1?1? pids?2?68?1
?
每一列的說明:
1)subsys_name:subsystem 的名字
2)hierarchy:subsystem 所關(guān)聯(lián)到的 cgroup 樹的 ID,如果多個(gè) subsystem 關(guān)聯(lián)到同一顆 cgroup 樹,那么他們的這個(gè)字段將一樣,比如這里的 cpu 和 cpuacct 就一樣,表示他們綁定到了同一顆樹。如果出現(xiàn)下面的情況,這個(gè)字段將為0:
當(dāng)前 subsystem 沒有和任何 cgroup 樹綁定
當(dāng)前 subsystem 已經(jīng)和 cgroup v2 的樹綁定
當(dāng)前 subsystem 沒有被內(nèi)核開啟
3)num_cgroups:subsystem 所關(guān)聯(lián)的 cgroup 樹中進(jìn)程組的個(gè)數(shù),也即樹上節(jié)點(diǎn)的個(gè)數(shù)
4)enabled:1 表示開啟,0 表示沒有被開啟(可以通過設(shè)置內(nèi)核的啟動(dòng)參數(shù) cgroup_disable 來控制 subsystem 的開啟)。
8.2 Cgroups 下的 CPU 子系統(tǒng)
cpu 子系統(tǒng)用于控制 cgroup 中所有進(jìn)程可以使用的 cpu 時(shí)間片。cpu subsystem 主要涉及5接口:cpu.cfs_period_us、cpu.cfs_quota_us、cpu.shares、cpu.rt_period_us、cpu.rt_runtime_us.cpu。
1)cfs_period_us:cfs_period_us 表示一個(gè) cpu 帶寬,單位為微秒。系統(tǒng)總 CPU 帶寬:cpu核心數(shù) * cfs_period_us cpu。
2)cfs_quota_us:cfs_quota_us 表示 Cgroup 可以使用的 cpu 的帶寬,單位為微秒。cfs_quota_us 為-1,表示使用的 CPU 不受 cgroup 限制。cfs_quota_us 的最小值為1ms(1000),最大值為1s。結(jié)合 cfs_period_us,就可以限制進(jìn)程使用的 cpu。例如配置 cfs_period_us=10000,而 cfs_quota_us=2000。那么該進(jìn)程就可以可以用2個(gè) cpu core。
3)cpu.shares:通過 cfs_period_us 和 cfs_quota_us 可以以絕對比例限制 cgroup 的 cpu 使用,即cfs_quota_us/cfs_period_us 等于進(jìn)程可以利用的 cpu cores,不能超過這個(gè)數(shù)值。而 cpu.shares 以相對比例限制 cgroup 的 cpu。例如:在兩個(gè) cgroup 中都將 cpu.shares 設(shè)定為 1 的任務(wù)將有相同的 CPU 時(shí)間,但在 cgroup 中將 cpu.shares 設(shè)定為 2 的任務(wù)可使用的 CPU 時(shí)間 是在 cgroup 中將 cpu.shares 設(shè)定為 1 的任務(wù)可使用的 CPU 時(shí)間的兩倍。
4)cpu.rt_runtime_us:以微秒(μs,這里以“us”代表)為單位指定在某個(gè)時(shí)間段中 cgroup 中的任務(wù)對 CPU 資源的最長連續(xù)訪問時(shí)間。建立這個(gè)限制是為了防止一個(gè) cgroup 中的任務(wù)獨(dú)占 CPU 時(shí)間。如果 cgroup 中的任務(wù)應(yīng)該可以每 5 秒中可有 4 秒時(shí)間訪問 CPU 資源,請將 cpu.rt_runtime_us 設(shè)定為 4000000,并將 cpu.rt_period_us 設(shè)定為 5000000。
5)cpu.rt_period_us:以微秒(μs,這里以“us”代表)為單位指定在某個(gè)時(shí)間段中 cgroup 對 CPU 資源訪問重新分配的頻率。如果某個(gè) cgroup 中的任務(wù)應(yīng)該每 5 秒鐘有 4 秒時(shí)間可訪問 CPU 資源,則請將 cpu.rt_runtime_us 設(shè)定為 4000000,并將 cpu.rt_period_us 設(shè)定為 5000000。注意 sched_rt_runtime_us 是實(shí)時(shí)任務(wù)的保證時(shí)間和最高占用時(shí)間,如果實(shí)時(shí)任務(wù)沒有使用,可以分配給非實(shí)時(shí)任務(wù),并且實(shí)時(shí)任務(wù)最終占用的時(shí)間不能超過這個(gè)數(shù)值,參考 Linux-85 關(guān)于 sched_rt_runtime_us 和 sched_rt_period_us。對 cpu.rt_period_us 參數(shù)的限制是必須小于父目錄中的同名參數(shù)值。對 cpu.rt_runtime_us 的限制是:
?
Sum_{i}?runtime_{i}?/?global_period?<=?global_runtime?/?global_period
?
即:
?
Sum_{i}?runtime_{i}?<=?global_runtime?
?
當(dāng)前的實(shí)時(shí)進(jìn)程調(diào)度算法可能導(dǎo)致部分實(shí)時(shí)進(jìn)程被餓死,如下A和B是并列的,A的運(yùn)行時(shí)時(shí)長正好覆蓋了B的運(yùn)行時(shí)間:
?
*?group?A:?period=100000us,?runtime=50000us -?this?runs?for?0.05s?once?every?0.1s ? *?group?B:?period=?50000us,?runtime=25000us -?this?runs?for?0.025s?twice?every?0.1s?(or?once?every?0.05?sec).
?
Real-Time group scheduling 中提出正在開發(fā) SCHED_EDF (Earliest Deadline First scheduling),優(yōu)先調(diào)度最先結(jié)束的實(shí)時(shí)進(jìn)程。
8.3 在 CentOS 中安裝 Cgroups
?
#若系統(tǒng)未安裝則進(jìn)行安裝,若已安裝則進(jìn)行更新。? yum?install?libcgroup? ? #查看運(yùn)行狀態(tài),并啟動(dòng)服務(wù)? [root@localhost?~]?service?cgconfig?status? Stopped? ? [root@localhost?~]?service?cgconfig?start? Starting?cgconfig?service:?[?OK?]? service?cgconfig?status?9?Running?1011? ? #查看是否安裝cgroup [root@localhost?~]?grep?cgroup?/proc/filesystems
?
8.4 查看 service 服務(wù)在哪個(gè) cgroup 組
?
systemctl?status?[pid]?|?grep?CGroup?23? cat?/proc/[pid]/cgroup? cd?/sys/fs/?&&?find?*?‐name?"*.procs"?‐exec?grep?[pid]?{}?/dev/null?;?2>?/dev/null? ? #查看進(jìn)程cgroup的最快方法是使用以下bash腳本按進(jìn)程名:? #!/bin/bash? THISPID=`ps?‐eo?pid,comm?|?grep?$1?|?awk?'{print?$1}'`? cat?/proc/$THISPID/cgroup
?
9. 如何使用 Cgroups
9.1 通過 systemctl 設(shè)置 cgroup
在使用命令 systemctl set-property 時(shí),可以使用 tab 補(bǔ)全:
?
$ systemctl set‐property user‐1000.slice AccuracySec= CPUAccounting= Environment= LimitCPU= LimitNICE= LimitSIGPEN DING= SendSIGKILL= BlockIOAccounting= CPUQuota= Group= LimitDATA= LimitNOFILE= LimitSTACK= U ser= BlockIODeviceWeight= CPUShares= KillMode= LimitFSIZE= LimitNPROC= MemoryA ccounting= WakeSystem= BlockIOReadBandwidth= DefaultDependencies= KillSignal= LimitLOCKS= LimitR SS= MemoryLimit= BlockIOWeight= DeviceAllow= LimitAS= LimitMEMLOCK= LimitRTPRIO= Nice= BlockIOWriteBandwidth= DevicePolicy= LimitCORE= LimitMSGQUEUE= LimitRTTIM E= SendSIGHUP=
?
這里有很多屬性可以設(shè)置,但并不是所有的屬性都是用來設(shè)置 cgroup 的,我們只需要關(guān)注 Block, CPU 和 Memory。
如果你想通過配置文件來設(shè)置 cgroup,service 可以直接在 /etc/systemd/system/xxx.service.d 目錄下面創(chuàng)建相應(yīng)的配置文件,slice 可以直接在 /run/systemd/system/xxx.slice.d 目錄下面創(chuàng)建相應(yīng)的配置文件。事實(shí)上通過 systemctl 命令行工具設(shè)置 cgroup 也會(huì)寫到該目錄下的配置文件中:
?
$?cat?/run/systemd/system/user‐1000.slice.d/50‐CPUQuota.conf? [Slice]? CPUQuota=20%
?
9.2 設(shè)置 CPU 資源的使用上限
如果想嚴(yán)格控制 CPU 資源,設(shè)置 CPU 資源的使用上限,即不管 CPU 是否繁忙,對 CPU 資源的使用都不能超過這個(gè)上限??梢酝ㄟ^以下兩個(gè)參數(shù)來設(shè)置:
1)cpu.cfs_period_us = 統(tǒng)計(jì) CPU 使用時(shí)間的周期,單位是微秒(us)
2)cpu.cfs_quota_us = 周期內(nèi)允許占用的 CPU 時(shí)間(指單核的時(shí)間,多核則需要在設(shè)置時(shí)累加)
systemctl 可以通過 CPUQuota 參數(shù)來設(shè)置 CPU 資源的使用上限。例如,如果你想將用戶 tom 的 CPU 資源使用上限設(shè)置為 20%,可以執(zhí)行以下命令:
?
$?systemctl?set‐property?user‐1000.slice?CPUQuota=20%
?
9.3 通過配置文件設(shè)置 cgroup(/etc/cgconfig.conf)
cgroup 配置文件所在位置 /etc/cgconfig.conf,其默認(rèn)配置文件內(nèi)容
?
mount?{ cpuset?=?/?cgroup?/?cpuset?; cpu?=?/?cgroup?/?cpu?; cpuacct?=?/?cgroup?/?cpuacct?; memory?=?/?cgroup?/?memory?; devices?=?/?cgroup?/?devices?; freezer?=?/?cgroup?/?freezer?; net_cls?=?/?cgroup?/?net_cls?; blkio?=?/?cgroup?/?blkio?; }
?
相當(dāng)于執(zhí)行命令:
?
mkdir?/cgroup/cpuset? mount?‐t?cgroup?‐o?cpuset?red?/cgroup/cpuset ……? mkdir?/cgroup/blkio? ? [root@localhost?~]?vi?/etc/cgrules.conf? [root@localhost?~]?echo?524288000?>?/cgroup/memory/foo/memory.limit_in_b?ytes?
?
使用 cgroup 臨時(shí)對進(jìn)程進(jìn)行調(diào)整,直接通過命令即可,如果要持久化對進(jìn)程進(jìn)行控制,即重啟后依然有效,需要寫進(jìn)配置文件 /etc/cgconfig.conf 及 /etc/cgrules.conf。
10. 查看 Cgroup
10.1 通過 systemd 查看 cgroup
1)systemd-cgls 命令:通過 systemd-cgls 命令來查看,它會(huì)返回系統(tǒng)的整體 cgroup 層級,cgroup 樹的最高層 由 slice 構(gòu)成,如下所示:
?
$?systemd‐cgls?‐‐no‐page? ? ├─1?/usr/lib/systemd/systemd?‐‐switched‐root?‐‐system?‐‐deserialize?22? ├─user.slice? │?├─user‐1000.slice? │?│?└─session‐11.scope? │?│?├─9507?sshd:?tom?[priv]? │?│?├─9509?sshd:?tom@pts/3? │?│?└─9510?‐bash? │?└─user‐0.slice? │?└─session‐1.scope? │?├─?6239?sshd:?root@pts/0? │?├─?6241?‐zsh? │?└─11537?systemd‐cgls?‐‐no‐page? └─system.slice?15?├─rsyslog.service? │?└─5831?/usr/sbin/rsyslogd?‐n? ├─sshd.service?18?│?└─5828?/usr/sbin/sshd?‐D? ├─tuned.service? │?└─5827?/usr/bin/python2?‐Es?/usr/sbin/tuned?‐l?‐P?21?├─crond.service? │?└─5546?/usr/sbin/crond?‐n
?
可以看到系統(tǒng) cgroup 層級的最高層由 user.slice 和 system.slice 組成。因?yàn)橄到y(tǒng)中沒有 運(yùn)行虛擬機(jī)和容器,所以沒有 machine.slice,所以當(dāng) CPU 繁忙時(shí),user.slice 和 system.slice 會(huì)各獲得 50% 的 CPU 使用時(shí)間。
user.slice 下面有兩個(gè)子 slice:user-1000.slice 和 user-0.slice,每個(gè)子 slice 都用 User ID (UID) 來命名,因此我們很容易識別出哪個(gè) slice 屬于哪個(gè)用戶。例如從上面的輸出信息中可以看出 user-1000.slice 屬于用戶 tom,user-0.slice 屬于用戶 root。
2)systemd-cgtop 命令:systemd-cgls 命令提供的只是 cgroup 層級的靜態(tài)信息快照,要想查看 cgroup 層級的動(dòng) 態(tài)信息,可以通過 systemd-cgtop 命令查看:
?
$?systemd‐cgtop? ? Path?Tasks?%CPU?Memory?Input/s?Output/s? /?161?1.2?161.0M?‐?‐?5?/system.slice?‐?0.1?‐?‐?‐? /system.slice/vmtoolsd.service?1?0.1?‐?‐?‐? /system.slice/tuned.service?1?0.0?‐?‐?‐? /system.slice/rsyslog.service?1?0.0?‐?‐?‐? /system.slice/auditd.service?1?‐?‐?‐?‐? /system.slice/chronyd.service?1?‐?‐?‐?‐? /system.slice/crond.service?1?‐?‐?‐?‐? /system.slice/dbus.service?1?‐?‐?‐?‐? /system.slice/gssproxy.service?1?‐?‐?‐?‐? /system.slice/lvm2‐lvmetad.service?1?‐?‐?‐?‐? /system.slice/network.service?1?‐?‐?‐?‐? /system.slice/polkit.service?1?‐?‐?‐?‐? /system.slice/rpcbind.service?1?‐?‐?‐?‐? /system.slice/sshd.service?1?‐?‐?‐?‐? /system.slice/system‐getty.slice/getty@tty1.service?1?‐?‐?‐?‐? /system.slice/systemd‐journald.service?1?‐?‐?‐?‐? /system.slice/systemd‐logind.service?1?‐?‐?‐?‐? /system.slice/systemd‐udevd.service?1?‐?‐?‐?‐? /system.slice/vgauthd.service?1?‐?‐?‐?‐? /user.slice?3?‐?‐?‐?‐? /user.slice/user‐0.slice/session‐1.scope?3?‐?‐?‐?‐? /user.slice/user‐1000.slice?3?‐?‐?‐?‐? /user.slice/user‐1000.slice/session‐11.scope?3?‐?‐?‐?‐? /user.slice/user‐1001.slice/session‐8.scope
?
scope systemd-cgtop 提供的統(tǒng)計(jì)數(shù)據(jù)和控制選項(xiàng)與 top 命令類似,但該命令只顯示那些開啟了 資源統(tǒng)計(jì)功能的 service 和 slice。
如果你想開啟 sshd.service 的資源統(tǒng)計(jì)功能,可以進(jìn)行如下操作:
?
$?systemctl?set‐property?sshd.service?CPUAccounting=true?MemoryAccounting=true? ? #該命令會(huì)在?/etc/systemd/system/sshd.service.d/?目錄下創(chuàng)建相應(yīng)的配置文件:? $?ll?/etc/systemd/system/sshd.service.d/? 總用量?8? 4?‐rw‐r‐‐r‐‐?1?root?root?28?5月?31?02:24?50‐CPUAccounting.conf? 4?‐rw‐r‐‐r‐‐?1?root?root?31?5月?31?02:24?50‐MemoryAccounting.conf? ? $?cat?/etc/systemd/system/sshd.service.d/50‐CPUAccounting.conf? [Service]? CPUAccounting=yes?1415? ? $?cat?/etc/systemd/system/sshd.service.d/50‐MemoryAccounting.conf? [Service]? MemoryAccounting=yes?1819? ? #配置完成之后,再重啟 sshd 服務(wù):? $?systemctl?daemon‐reload?21?$?systemctl?restart?sshd
?
這時(shí)再重新運(yùn)行 systemd‐cgtop 命令,就能看到 sshd 的資源使用統(tǒng)計(jì)了。
10.2 通過 proc 查看 cgroup
如何查看當(dāng)前進(jìn)程屬于哪些 cgroup 可以通過查看 /proc/[pid]/cgroup(since Linux 2.6.24)知道指定進(jìn)程屬于哪些cgroup,如下:
?
$?cat?/proc/777/cgroup? ? 11/? 10/? 9/system.slice/cron.service? 8/system.slice/cron.service? 7/?7?6:net_cls,net_prio:/? 5/system.slice/cron.service? 4/? 3:cpu,cpuacct:/system.slice/cron.service? 2/system.slice/cron.service? 1:name=systemd:/system.slice/cron.service
?
每一行包含用冒號隔開的三列,他們的意思分別是:
cgroup樹的ID :和cgroup樹綁定的所有subsystem :進(jìn)程在cgroup樹中的路徑
1)cgroup 樹的 ID,和 /proc/cgroups 文件中的 ID 一一對應(yīng)。
2)和 cgroup 樹綁定的所有 subsystem,多個(gè) subsystem 之間用逗號隔開。這里 name=systemd 表示沒有和任何 subsystem 綁定,只是給他起了個(gè)名字叫 systemd。
3)進(jìn)程在 cgroup 樹中的路徑,即進(jìn)程所屬的 cgroup,這個(gè)路徑是相對于掛載點(diǎn)的相對路徑。
10.3 通過 /sys 查看 cgroup
查看 cgroup 下 CPU 資源的使用上限:
?
$?cat?/sys/fs/cgroup/cpu,cpuacct/user.slice/user‐1000.slice/cpu.cfs_perio?d_us? 100000? ? $?cat?/sys/fs/cgroup/cpu,cpuacct/user.slice/user‐1000.slice/cpu.cfs_quota?_us? 20000?
?
這表示用戶 tom 在一個(gè)使用周期內(nèi)(100 毫秒)可以使用 20 毫秒的 CPU 時(shí)間。不管 CPU 是否空閑,該用戶使用的 CPU 資源都不會(huì)超過這個(gè)限制。
CPUQuota 的值可以超過 100%,例如:如果系統(tǒng)的 CPU 是多核,且 CPUQuota 的值為 200%,那么該 slice 就能夠使用 2 核的 CPU 時(shí)間。
審核編輯:湯梓紅
評論
查看更多