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