Docker核心原理之cgroups
cgroups資源限制
上一篇文章中,我們了解了Docker的資源隔離技術(shù)namespace,通過系統(tǒng)調(diào)用構(gòu)建了一個相對隔離的shell環(huán)境。也可以稱之為一個簡單的容器。接下來將講解另一個強(qiáng)大的內(nèi)核工具-cgroups。它不僅可以限制被namespace隔離起來的資源,還可以為資源設(shè)置權(quán)重、計(jì)算使用量、操控任務(wù)(進(jìn)程或線程)啟停等。
1.cgroups是什么
cgroups顧名思義就是把任務(wù)放到一個組里面統(tǒng)一加以控制。官方的定義如下:
cgroups是Linux內(nèi)核提供的一種機(jī)制,這種機(jī)制可以根據(jù)需求吧一系列系統(tǒng)任務(wù)及其子任務(wù)整合(或分隔)到按資源劃分等級的不同組中,從而為系統(tǒng)資源管理提供一個統(tǒng)一的框架。
通俗地說,cgroups可以限制,記錄任務(wù)組做使用的無力資源(包括CPU、Memory、IO等),為容器實(shí)現(xiàn)虛擬化提供了保證,是構(gòu)建Docker等一系列虛擬化管理工具的基石。
對開發(fā)者來說,cgroups有以下4個特點(diǎn):
- cgroups的API以一個偽文件系統(tǒng)的方式實(shí)現(xiàn),用戶態(tài)的程序可以通過文件的操作實(shí)現(xiàn)cgroups的組織管理。
- cgroups的組織管理操作單元可以細(xì)粒度到線程級別,另外用戶可以創(chuàng)建和銷毀cgroup,從而實(shí)現(xiàn)資源的再分配和管理。
- 所有資源管理的功能都以子系統(tǒng)的方式實(shí)現(xiàn),接口統(tǒng)一。
- 子任務(wù)創(chuàng)建之初與父任務(wù)處于同一個cgroups的控制組。
本質(zhì)上來說,cgroups是內(nèi)核附加在程序上的一系列鉤子(hook),通過程序運(yùn)行時對資源的調(diào)度觸發(fā)相應(yīng)的鉤子以達(dá)到資源追蹤和限制的目的。
2.cgroups的作用
實(shí)現(xiàn)cgroups的主要目的是為了不同的用戶層面的資源管理,提供一個統(tǒng)一化的接口。從單個任務(wù)的資源控制到操作系統(tǒng)層面的虛擬化,cgroups提供了以下四大功能:
- 資源限制:cgroups可以對任務(wù)使用的資源總額進(jìn)行限制。如設(shè)定應(yīng)用運(yùn)行時使用內(nèi)存的上限,一旦超過這個配額就發(fā)出OOM(Out Of Memory)提示。
- 優(yōu)先級分配:通過分配的CPU時間片數(shù)量及磁盤IO寬帶大小,實(shí)際上就相當(dāng)于控制了任務(wù)運(yùn)行的優(yōu)先級。
- 資源統(tǒng)計(jì):cgroups可以統(tǒng)計(jì)系統(tǒng)的資源使用量,如CPU使用時長、內(nèi)存用量等,這個功能非常適用于計(jì)費(fèi)。
- 任務(wù)控制:cgroups可以對任務(wù)執(zhí)行掛起、恢復(fù)等操作。
3.cgroups術(shù)語表
- task(任務(wù)):在cgroups的術(shù)語中,任務(wù)表示一個進(jìn)程或線程。
- cgroup(控制組):cgroups中的資源控制都以cgroup為單位實(shí)現(xiàn)。cgroup表示按某種資源控制標(biāo)準(zhǔn)劃分而成的控制組,包含了一個或多個子系統(tǒng)。一個任務(wù)可以加入某個cgroup,也可以從某個cgroup遷移到另外一個cgroup。
- subsystem(子系統(tǒng)):cgroups中的子系統(tǒng)就是一個資源調(diào)度控制器。比如CPU子系統(tǒng)可以控制CPU時間分配,內(nèi)存子系統(tǒng)可以限制cgroup內(nèi)存使用量。
- hiererchy(層級):層級由一系列cgroup以一個樹狀結(jié)構(gòu)排列而成,每個層級通過綁定對應(yīng)的子系統(tǒng)進(jìn)行資源控制。層級中的cgroup幾點(diǎn)可以包括零或多個這幾點(diǎn),子節(jié)點(diǎn)繼承父節(jié)點(diǎn)掛載的子系統(tǒng)。整個操作系統(tǒng)可以有多個層級。
4.組織結(jié)構(gòu)與基本規(guī)則
上一篇文章已經(jīng)介紹過,傳統(tǒng)的Unix任務(wù)管理,實(shí)際上是先啟動init任務(wù)作為根基點(diǎn),再由init節(jié)點(diǎn)創(chuàng)建子任務(wù)作為子節(jié)點(diǎn),而每個子節(jié)點(diǎn)又可以創(chuàng)建新的子節(jié)點(diǎn),如此往復(fù),形成一個樹狀結(jié)構(gòu)。而系統(tǒng)中的多個cgroup也構(gòu)成類似的樹狀結(jié)構(gòu),子節(jié)點(diǎn)從父節(jié)點(diǎn)繼承屬性。
它們最大的不同在于,系統(tǒng)中的多個cgroup構(gòu)成的層級并非單根結(jié)構(gòu),可以允許存在多個。如果任務(wù)模型由init作為根節(jié)點(diǎn)構(gòu)成一棵樹,那么系統(tǒng)中的多個cgroup則是由多個cgroup則是由多個層級構(gòu)成的森林。這樣做的目的很好理解,如果只有一個層級,那么所有的任務(wù)都將被迫綁定其上的所有子系統(tǒng),這會給某些任務(wù)造成不必要的限制。在Docker中,每個子系統(tǒng)獨(dú)自構(gòu)成一個層級,這樣做非常易于管理。
5.子系統(tǒng)簡介
子系統(tǒng)實(shí)際上就是cgroups的資源控制系統(tǒng),每個子系統(tǒng)獨(dú)立地控制一種資源,目前Docker使用了如下9種子系統(tǒng),其中net_cls子系統(tǒng)在內(nèi)核中已經(jīng)廣泛實(shí)現(xiàn),但在Docker中尚未使用,Docker在網(wǎng)絡(luò)方案的控制方式在以后的文章中會繼續(xù)介紹。
- blkio: 可以為塊設(shè)備設(shè)定輸入/輸出限制,比如物理驅(qū)動設(shè)備(包括磁盤、固態(tài)硬盤、USB等)。
- cpu:使用調(diào)度程序控制任務(wù)對CPU的使用。
- cpuacct:自動生成cgroup中任務(wù)對CPU資源使用的情況的報(bào)告。
- cpuset:可以為cgroup中的任務(wù)分配獨(dú)立的CPU(針對多處理器系統(tǒng))和內(nèi)存。
- devices:可以啟動或關(guān)閉cgroup中任務(wù)對設(shè)備的訪問。
- freezer:可以掛起或恢復(fù)cgroup中的任務(wù)。
- memory:可以設(shè)定cgroup中任務(wù)對內(nèi)存的使用量的限定,并且自動生成這些任務(wù)對內(nèi)存資源使用情況的報(bào)告。
- perf_event:使用后使cgroup中的任務(wù)可以進(jìn)行統(tǒng)一的性能測試。(Pref:linux CPU性能探測器)
- net_cls:Docker沒有直接使用它,它通過使用等級識別符(classid)標(biāo)記網(wǎng)絡(luò)數(shù)據(jù)包,從而允許Linux流量控制程序(Traffic Controller,TC)識別從具體cgroup中生成的數(shù)據(jù)包。
上述子系統(tǒng)如何使用雖然很重要,但是Docker并沒有對cgroup本身做增強(qiáng),容器用戶一般也不需要直接操作cgroup。這里我只是大致說明下操作流程,讓讀者有一個感性的認(rèn)識。
Linux中cgroup的實(shí)現(xiàn)形式表現(xiàn)為一個文件系統(tǒng),因此需要mount這個文件系統(tǒng)才能使用,掛載成功后就能看到各類子系統(tǒng)。
6.cgroups實(shí)現(xiàn)方式及工作原理
在對cgroups規(guī)則和自通有一定了解以后,下面簡單介紹操作系統(tǒng)內(nèi)核級別上cgroups的工作原理,希望能有助于讀者理解cgroups如何對Docker容器中的進(jìn)程產(chǎn)生作用。
cgroups的實(shí)現(xiàn)本質(zhì)上是給任務(wù)掛上鉤子,當(dāng)任務(wù)運(yùn)行的過程中涉及某種資源時,就會觸發(fā)鉤子上所附帶的子系統(tǒng)進(jìn)行檢測,根據(jù)資源列別不同,使用對應(yīng)的技術(shù)進(jìn)行資源限制和優(yōu)先級分配。
- cgroups如何判斷資源超限及超出限額后的措施
對于不同的系統(tǒng)資源,cgroups提供了統(tǒng)一的接口對資源進(jìn)行控制和統(tǒng)計(jì),但限制的具體方式則不盡相同。比如memorary子系統(tǒng),會描述內(nèi)存狀態(tài)的“mm_struct”結(jié)構(gòu)體中記錄它所屬的cgroup,當(dāng)進(jìn)程需要申請更多內(nèi)存時,就會觸發(fā)cgroup用量檢測,用量超過cgroup規(guī)定的限額,則拒絕用戶的內(nèi)存申請,否則就給予相應(yīng)內(nèi)存并在cgroup的統(tǒng)計(jì)信息中記錄。實(shí)際實(shí)現(xiàn)要比上述描述復(fù)雜的多,不僅需要考慮內(nèi)存的分配和回收,還需要考慮不同類型的內(nèi)存如cache和swap等。
進(jìn)程所需的內(nèi)存超過它所屬的cgroup最大限額以后,如果設(shè)置了OOM Control(內(nèi)存超限控制),那么進(jìn)程就會收到OOM信號并結(jié)束;否則進(jìn)程就會被掛起,進(jìn)入睡眠狀態(tài),進(jìn)入睡眠狀態(tài),直到cgroup中其他進(jìn)程釋放了足夠的內(nèi)存資源為止。Docker中默認(rèn)是開啟OOM Control的。其他子系統(tǒng)的實(shí)現(xiàn)與此類似,cgroups提供了多種資源限制的策略供用戶選擇。
- cgroup與任務(wù)之間的關(guān)聯(lián)關(guān)系
實(shí)現(xiàn)上,cgroup與任務(wù)之間是多對多關(guān)系,所以它們并不直接關(guān)聯(lián),而是通過一個中間結(jié)構(gòu)把雙向的關(guān)聯(lián)信息記錄起來。每個任務(wù)結(jié)構(gòu)體tsak_struct中都包含了一個指針,可以查到對應(yīng)的cgroup的情況,同時也可以查詢到各個子系統(tǒng)的狀態(tài),這些子系統(tǒng)狀態(tài)中也包含了找到任務(wù)的指針,不同類型的子系統(tǒng)按需定義本身的控制信息結(jié)構(gòu)體,最終在地定義的結(jié)構(gòu)體中吧子系統(tǒng)狀態(tài)指針包含進(jìn)去,然后內(nèi)核通過container_of(這個宏可以通過一個結(jié)構(gòu)體的成員找到結(jié)構(gòu)體自身)等宏定義來獲取對應(yīng)的結(jié)構(gòu)體,關(guān)聯(lián)到任務(wù),從此達(dá)到資源限制的目的。同時,為了讓cgroups便于用戶理解和使用,也為了用精簡的內(nèi)核代買為cgroup提供熟悉的權(quán)限和命名空間管理,內(nèi)核開發(fā)者們按照Linux虛擬文件轉(zhuǎn)化器(Virtual Filesystem Switch,VFS)接口實(shí)現(xiàn)了一套名為cgroup的文件系統(tǒng),非常巧的用來表示cgroups的層級概念,把各個子系統(tǒng)的實(shí)現(xiàn)都瘋撞到文件系統(tǒng)的各項(xiàng)操作中。
- Docker在使用cgroup時的注意事項(xiàng)
在實(shí)際使用過程中,Docker需要通過掛載cgroup文件系統(tǒng)新建一個層級結(jié)構(gòu),掛載時指定要綁定的子系統(tǒng)。把cgroup文件系統(tǒng)掛載上以后,就可以像操作文件一樣對cgroup的層級進(jìn)行瀏覽和操作管理(包括權(quán)限管理、子文件管理等)。除了cgroup文件系統(tǒng)以外,內(nèi)核沒有為cgroups的訪問和操作添加任何系統(tǒng)調(diào)用。
- /sys/fs/cgroup/cpu/docker/下文件的作用
前面已經(jīng)說過,以資源開頭的文件都是用來限制這個cgroup下任務(wù)的可用配置文件。
一個cgroup創(chuàng)建完成,不管綁定了何種子系統(tǒng),其目錄下都會生成以下幾個文件,用來描述cgroup的相應(yīng)信息。同樣,把相應(yīng)信息寫入這些配置文件中就可以生效。
本文由淺入深的講解了cgroups,從cgroups是什么,到cgroups要怎么用,最后對大量的cgroup子系統(tǒng)進(jìn)行了講解。可以看到內(nèi)核對cgroups的支持已經(jīng)較多,但是依舊有許多工作要完善。如網(wǎng)絡(luò)方面目前通過TC(Traffic Controller)來控制,未來需要統(tǒng)一整合;由縣級調(diào)度方面依舊有很大的改進(jìn)空間。
總結(jié)
以上是生活随笔為你收集整理的Docker核心原理之cgroups的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker核心原理之namespace
- 下一篇: 在Ubuntu系统中安装Docker