【重识云原生】第六章容器6.1.7.2节——cgroups原理剖析
??《重識云原生系列》專題索引:
?第四章云網絡4.9.1節——網絡卸載加速技術綜述
第四章云網絡4.9.2節——傳統網絡卸載技術
第四章云網絡4.9.3.1節——DPDK技術綜述
第四章云網絡4.9.3.2節——DPDK原理詳解
第四章云網絡4.9.4.1節——智能網卡SmartNIC方案綜述
第四章云網絡4.9.4.2節——智能網卡實現
第六章容器6.1.1節——容器綜述
第六章容器6.1.2節——容器安裝部署
第六章容器6.1.3節——Docker常用命令
第六章容器6.1.4節——Docker核心技術LXC
第六章容器6.1.5節——Docker核心技術Namespace
第六章容器6.1.6節—— Docker核心技術Chroot
第六章容器6.1.7.1節——Docker核心技術cgroups綜述
第六章容器6.1.7.2節——cgroups原理剖析
第六章容器6.1.7.3節——cgroups數據結構剖析
第六章容器6.1.7.4節——cgroups使用
第六章容器6.1.8節——Docker核心技術UnionFS
第六章容器6.1.9節——Docker鏡像技術剖析
第六章容器6.1.10節——DockerFile解析
第六章容器6.1.11節——docker-compose容器編排
第六章容器6.1.12節——Docker網絡模型設計
第六章容器6.2.1節——Kubernetes概述
第六章容器6.2.2節——K8S架構剖析
第六章容器6.3.1節——K8S核心組件總述
第六章容器6.3.2節——API Server組件
第六章容器6.3.3節——Kube-Scheduler使用篇
第六章容器6.3.4節——etcd組件
第六章容器6.3.5節——Controller Manager概述
第六章容器6.3.6節——kubelet組件
第六章容器6.3.7節——命令行工具kubectl
第六章容器6.3.8節——kube-proxy
第六章容器6.4.1節——K8S資源對象總覽
第六章容器6.4.2.1節——pod詳解
第六章容器6.4.2.2節——Pod使用(上)
第六章容器6.4.2.3節——Pod使用(下)
第六章容器6.4.3節——ReplicationController
第六章容器6.4.4節——ReplicaSet組件
第六章容器基礎6.4.5.1節——Deployment概述
第六章容器基礎6.4.5.2節——Deployment配置詳細說明
第六章容器基礎6.4.5.3節——Deployment實現原理解析
第六章容器基礎6.4.6節——Daemonset
第六章容器基礎6.4.7節——Job
第六章容器基礎6.4.8節——CronJob
2 cgroups原理解析
????????上面是說的cgroups 是內核提供的功能,但現在我們在用戶空間想使用的是cgroup的功能。其原理是:linux 內核有一個很強大的模塊叫做VFS(vritual File System),VFS 把具體的文件系統的細節隱藏起來,給用戶態進程提供一個完備的文件系統API接口。linux 也是通過VFS 把cgroups 功能暴漏給用戶態進程的,cgroups 與VFS 之間的銜接部分叫做cgroups 文件系統。
????????用戶態進程對groups 文件系統的操作,通過VFS 轉換成cgroups 層級結構的維護。
2.1 cgroups 層級樹的四大規則
????????傳統的進程啟動,是以init為根節點,也叫父進程,由它來創建子進程,作為子節點,而每個子節點還可以創建新的子節點,這樣構成了樹狀結構。而cgroup的結構也是類似的,子節點繼承父節點的屬性。他們最大的不同在于,系統的cgroup構成的層級樹允許有多個存在,如果進程模型是init為根節點形成一個樹,那cgroup的模型由多個層級樹來構成。
????????內核使用 cgroup 結構體來表示一個 control group 對某一個或者某幾個 cgroups 子系統的資源限制。cgroup 結構體可以組織成一顆樹的形式,每一棵cgroup 結構體組成的樹稱之為一個 cgroups 層級樹。
1. 同一個cgroups層級樹可以 attach 一個或者幾個 cgroups 子系統(subsystem),當前層級樹可以對其 attach 的 cgroups 子系統進行資源的限制。每一個 cgroups 子系統只能被 attach 到一個層級樹中。
2. 創建了 cgroups 層級樹中的節點(cgroup 結構體)之后,可以把進程加入到某一個節點的控制任務列表中,一個節點的控制列表中的所有進程都會受到當前節點的資源限制。同時某一個進程也可以被加入到不同的 cgroups 層級樹的節點中,因為不同的 cgroups 層級樹可以負責不同的系統資源。所以說進程和 cgroup 結構體是一個多對多的關系。
????????上面這個圖從整體結構上描述了進程與 cgroups 之間的關系。最下面的P代表一個進程。每一個進程的描述符中有一個指針指向了一個輔助數據結構css_set(cgroups subsystem set)。 指向某一個css_set的進程會被加入到當前css_set的進程鏈表中。一個進程只能隸屬于一個css_set,一個css_set可以包含多個進程,隸屬于同一css_set的進程受到同一個css_set所關聯的資源限制。
????????上圖中的”M×N Linkage”說明的是css_set通過輔助數據結構可以與 cgroups 節點進行多對多的關聯。但是 cgroups 的實現不允許css_set同時關聯同一個cgroups層級樹下多個節點。 這是因為 cgroups 對同一種資源不允許有多個限制配置。
????????一個css_set關聯多個 cgroups 層級樹的節點時,表明需要對當前css_set下的進程進行多種資源的控制。而一個 cgroups 節點關聯多個css_set時,表明多個css_set下的進程列表受到同一份資源的相同限制。
3. 一個task不能存在于同一個hierarchy的不同cgroup,但可以存在在不同hierarchy中的多個cgroup
????????系統每次新建一個hierarchy(即層級樹)時,該系統上的所有task默認構成了這個新建的hierarchy的初始化cgroup,這個cgroup也稱為root cgroup。
????????對于你創建的每個hierarchy,task只能存在于其中一個cgroup中,即一個task不能存在于同一個hierarchy的不同cgroup中,但是一個task可以存在在不同hierarchy中的多個cgroup中。
????????如果操作時把一個task添加到同一個hierarchy中的另一個cgroup中,則會從第一個cgroup中移除。
????????如下圖,cpu和memory被附加到cpu_mem_cg的hierarchy。而net_cls被附加到net hierarchy。并且httpd進程被同時加到了cpu_mem_cg hierarchy的cg1 cgroup中和net hierarchy的cg3 cgroup中。并通過兩個hierarchy的subsystem分別對httpd進程進行cpu,memory及網絡帶寬的限制。
4. 子task繼承父task cgroup的關系
????????系統中的任何一個task(Linux中的進程)fork自己創建一個子task(子進程)時,子task會自動的繼承父task cgroup的關系,在同一個cgroup中,但是子task可以根據需要移到其它不同的cgroup中。父子task之間是相互獨立不依賴的。
????????如下圖,httpd進程在cpu_and_mem hierarchy的/cg1 cgroup中并把PID 4537寫到該cgroup的tasks中。
????????之后httpd(PID=4537)進程fork一個子進程httpd(PID=4840)與其父進程在同一個hierarchy的統一個cgroup中,但是由于父task和子task之間的關系獨立不依賴的,所以子task可以移到其它的cgroup中。
?2.2 cgroup 的組成
????????cgroup 代表“控制組”,并且不會使用大寫。cgroup 是一種分層組織進程的機制, 沿層次結構以受控的方式分配系統資源。我們通常使用單數形式用于指定整個特征,也用作限定符如 “cgroup controller” 。
????????cgroup 主要有兩個組成部分:
- core - 負責分層組織過程;
- controller - 通常負責沿層次結構分配特定類型的系統資源。每個 cgroup 都有一個?cgroup.controllers?文件,其中列出了所有可供 cgroup 啟用的控制器。當在?cgroup.subtree_control?中指定多個控制器時,要么全部成功,要么全部失敗。在同一個控制器上指定多項操作,那么只有最后一個生效。每個 cgroup 的控制器銷毀是異步的,在引用時同樣也有著延遲引用的問題;
????????所有 cgroup 核心接口文件都以?cgroup?為前綴。每個控制器的接口文件都以控制器名稱和一個點為前綴。控制器的名稱由小寫字母和“”組成,但永遠不會以“”開頭。
2.2.1 cgroup 的核心文件
- cgroup.type - (單值)存在于非根 cgroup 上的可讀寫文件。通過將“threaded”寫入該文件,可以將 cgroup 轉換為線程 cgroup,可選擇 4 種取值,如下:
- domain - 一個正常的有效域 cgroup
- domain threaded - 線程子樹根的線程域 cgroup
- domain invalid - 無效的 cgroup
- threaded - 線程 cgroup,線程子樹
- cgroup.procs - (換行分隔)所有 cgroup 都有的可讀寫文件。每行列出屬于 cgroup 的進程的 PID。PID 不是有序的,如果進程移動到另一個 cgroup ,相同的 PID 可能會出現不止一次;
- cgroup.controllers - (空格分隔)所有 cgroup 都有的只讀文件。顯示 cgroup 可用的所有控制器;
- cgroup.subtree_control - (空格分隔)所有 cgroup 都有的可讀寫文件,初始為空。如果一個控制器在列表中出現不止一次,最后一個有效。當指定多個啟用和禁用操作時,要么全部成功,要么全部失敗。
- 以“+”為前綴的控制器名稱表示啟用控制器
- 以“-”為前綴的控制器名稱表示禁用控制器
- cgroup.events - 存在于非根 cgroup 上的只讀文件。
- populated - cgroup 及其子節點中包含活動進程,值為1;無活動進程,值為0.
- frozen - cgroup 是否被凍結,凍結值為1;未凍結值為0.
- cgroup.threads - (換行分隔)所有 cgroup 都有的可讀寫文件。每行列出屬于 cgroup 的線程的 TID。TID 不是有序的,如果線程移動到另一個 cgroup ,相同的 TID 可能會出現不止一次。
- cgroup.max.descendants - (單值)可讀寫文件。最大允許的 cgroup 子節點數量。
- cgroup.max.depth - (單值)可讀寫文件。低于當前節點最大允許的樹深度。
- cgroup.stat - 只讀文件。
- nr_descendants - 可見后代的 cgroup 數量。
- nr_dying_descendants - 被用戶刪除即將被系統銷毀的 cgroup 數量。
- cgroup.freeze - (單值)存在于非根 cgroup 上的可讀寫文件。默認值為0。當值為1時,會凍結 cgroup 及其所有子節點 cgroup,會將相關的進程關停并且不再運行。凍結 cgroup 需要一定的時間,當動作完成后, cgroup.events 控制文件中的 “frozen” 值會更新為“1”,并發出相應的通知。cgroup 的凍結狀態不會影響任何 cgroup 樹操作(刪除、創建等);
- cgroup.kill - (單值)存在于非根 cgroup 上的可讀寫文件。唯一允許值為1,當值為1時,會將 cgroup 及其所有子節點中的 cgroup 殺死(進程會被 SIGKILL 殺掉)。一般用于將一個 cgroup 樹殺掉,防止葉子節點遷移;
2.3子系統接口/參數
2.3.1 cpu子系統:用于限制進程的 CPU 利用率
CPU資源的控制有兩種策略:
- 一種是完全公平調度 (CFS:Completely Fair Scheduler)策略,提供了限額和按比例分配兩種方式進行資源控制;
- 另一種是實時調度(Real-Time Scheduler)策略,針對實時進程按周期分配固定的運行時間。配置時間都以微秒(μs)為單位,文件名中用us表示。
CFS調度策略下的配置:
- 設定CPU使用周期使用時間上限
- cpu.cfs_period_us:規定CPU的時間周期(單位是微秒)。最大值是1秒,最小值是1000微秒。如果在一個單CPU的系統內,要保證一個cgroup 內的任務在1秒的CPU周期內占用0.2秒的CPU時間,可以通過設置cpu.cfs_quota_us 為200000和cpu.cfs_period_us 為 1000000。必須與cfs_quota_us配合使用。
- cpu.cfs_quota_us :在單位時間內(即cpu.cfs_period_us設定值)可用的CPU最大時間(單位是微秒)。cpu.cfs_quota_us值可以大于cpu.cfs_period_us值,例如在一個雙CPU的系統內,想要一個cgroup內的進程充分的利用2個CPU,可以設定cpu.cfs_quota_us為 200000 及cpu.cfs_period_us為 100000,當設定cpu.cfs_quota_us為-1時,表明不受限制,同時這也是默認值。
- cpu.stat:統計信息,包含nr_periods(表示經歷了幾個cfs_period_us周期)、nr_throttled(表示task被限制的次數)及throttled_time(表示task被限制的總時長)。
- 按權重比例設定CPU的分配
- cpu.shares:cpu比重分配。通過一個整數的數值來調節cgroup所占用的cpu時間。例如,有2個cgroup(假設為CPU1,CPU2),其中一個(CPU1)cpu.shares設定為100另外一個(CPU2)設為200,那么CPU2所使用的cpu時間將是CPU1所使用時間的2倍。cpu.shares?的值必須為2或者高于2。
????????RT調度策略下的配置 實時調度策略與公平調度策略中的按周期分配時間的方法類似,也是在周期內分配一個固定的運行時間。
- cpu.rt_period_us :設定周期時間。
- cpu.rt_runtime_us:設定周期中的運行時間。
2.3.2 cpuacct子系統:用于統計各個 Cgroup 的 CPU 使用情況
????????這個子系統的配置是cpu子系統的補充,提供CPU資源用量的統計,時間單位都是納秒。
- cpuacct.stat:統計cgroup中所有任務的用戶和內核分別使用CPU的時長
- cpuacct.usage:統計cgroup中所有任務的CPU使用時長(納秒)
- cpuacct.usage_percpu:統計cgroup中所有任務使用的每個cpu的時間(納秒)
2.3.3 cpuset子系統:為一組進程分配指定的CPU和內存節點
????????為task分配獨立CPU資源的子系統,參數較多,這里只選講兩個必須配置的參數,同時Docker中目前也只用到這兩個。
- cpuset.cpus:允許cgroup中的進程使用的CPU列表。如0-2,16代表?0,1,2,16這4個CPU
- cpuset.mems:允許cgroup中的進程使用的內存節點列表。如0-2,16代表 0,1,2,16這4個可用節點
- cpuset.memory_migrate:當cpuset.mems變化時內存頁上的數據是否遷移(默認值0,不遷移;1,遷移)
- cpuset.cpu_exclusive:cgroup是否獨占cpuset.cpus 中分配的cpu 。(默認值0,共享;1,獨占),如果設置為1,其他cgroup內的cpuset.cpus值不能包含有該cpuset.cpus內的值
- cpuset.mem_exclusive:是否獨占memory,(默認值0,共享;1,獨占)
- cpuset.mem_hardwall:cgroup中任務的內存是否隔離,(默認值0,不隔離;1,隔離,每個用戶的任務將擁有獨立的空間)
- cpuset.sched_load_balance:cgroup的cpu壓力是否會被平均到cpuset中的多個cpu上。(默認值1,啟用負載均衡;0,禁用。)
2.3.4 memory子系統:限制cgroup所能使用的內存上限
- memory.limit_in_bytes:設定最大的內存使用量,可以加單位(k/K,m/M,g/G)不加單位默認為bytes
- memory.soft_limit_in_bytes:和 memory.limit_in_bytes 的差異是,這個限制并不會阻止進程使用超過限額的內存,只是在系統內存不足時,會優先回收超過限額的進程占用的內存,使之向限定值靠攏。該值應小于memory.limit_in_bytes設定值
- memory.memsw.limit_in_bytes:設定最大的內存+swap的使用量
- memory.oom_control:當進程出現Out of Memory時,是否進行kill操作。默認值0,kill;設置為1時,進程將進入睡眠狀態,等待內存充足時被喚醒
- memory.force_empty:當設置為0時,清空該group的所有內存頁;該選項只有在當前group沒有tasks才可以使用
- memory.stat:統計內存使用情況。各項單位為字節
????????統計相關特性:
- memory.usage_bytes:報???告???該??? cgroup中???進???程???使???用???的???當???前???總???內???存???用???量(以字節為單位)。
- memory.max_usage_bytes:報???告???該??? cgroup 中???進???程???使???用???的???最???大???內???存???用???量。
- memory.failcnt:報???告???內???存???達???到???在??? memory.limit_in_bytes設???定???的???限???制???值???的???次???數???。
- memory.stat:包含大量的內存統計數據。各項單位為字節。
- cache:頁???緩???存???,包???括??? tmpfs(shmem),單位為字節。
- rss:匿???名???和??? swap 緩???存???,不???包???括??? tmpfs(shmem),單位為字節。
- mapped_file:memory-mapped 映???射???的???文???件???大???小???,包???括??? tmpfs(shmem),單???位???為???字???節???。
- pgpgin:存???入???內???存???中???的???頁???數???。
- pgpgout:從???內???存???中???讀???出???的???頁???數。
- swap:swap 用???量???,單???位???為???字???節???。
- active_anon:在???活???躍???的???最???近???最???少???使???用???(least-recently-used,LRU)列???表???中???的???匿???名???和??? swap 緩???存???,包???括??? tmpfs(shmem),單???位???為???字???節???。
- inactive_anon:不???活???躍???的??? LRU 列???表???中???的???匿???名???和??? swap 緩???存???,包???括??? tmpfs(shmem),單???位???為???字???節。
- active_file:活???躍??? LRU 列???表???中???的??? file-backed 內???存???,以???字???節???為???單???位。
- inactive_file:不???活???躍??? LRU 列???表???中???的??? file-backed 內???存???,以???字???節???為???單???位。
- unevictable:無???法???再???生???的???內???存???,以???字???節???為???單???位???。
- hierarchical_memory_limit:包???含??? memory cgroup 的???層???級???的???內???存???限???制???,單???位???為???字???節???。
- hierarchical_memsw_limit:包???含??? memory cgroup 的???層???級???的???內???存???加??? swap 限???制???,單???位???為???字???節???。
2.3.5 blkio子系統:限制cgroup對IO的使用
- blkio.weight:設置權值,范圍在[100, 1000],屬于比重分配,不是絕對帶寬。因此只有當不同 Cgroup 爭用同一個 阻塞設備時才起作用
- blkio.weight_device:對具體設備設置權值。它會覆蓋上面的選項值
- blkio.throttle.read_bps_device:對具體的設備,設置每秒讀磁盤的帶寬上限
- blkio.throttle.write_bps_device:對具體的設備,設置每秒寫磁盤的帶寬上限
- blkio.throttle.read_iops_device:對具體的設備,設置每秒讀磁盤的IOPS帶寬上限
- blkio.throttle.write_iops_device:對具體的設備,設置每秒寫磁盤的IOPS帶寬上限
2.3.6 devices子系統:限定cgroup內的進程可以訪問的設備
- devices.allow:允許訪問的設備。文件包括4個字段:type(設備類型), major(主設備號), minor(次設備號), and access(訪問方式);
- type
- a — 適用所有設備,包括字符設備和塊設備
- b — 塊設備
- c — 字符設備
- major, minor
- 9:*
- *:*
- 8:1
- access
- r — 讀
- w — 寫
- m — 創建不存在的設備
- devices.deny:禁止訪問的設備,格式同devices.allow;
- devices.list:顯示目前允許被訪問的設備列表;
2.3.7 freezer子系統:暫停或恢復任務
- freezer.state:當前cgroup中進程的狀態
- FROZEN:掛起進程
- FREEZING:進程正在掛起中
- THAWED:激活進程
1. 掛起進程時,會連同子進程一同掛起。
2. 不能將進程移動到處于FROZEN狀態的cgroup中。
3. 只有FROZEN和THAWED可以被寫進freezer.state中, FREEZING則不能。
2.4 cgroup 文件系統實現
????????VFS虛擬文件系統轉換,處理與Unix標準文件系統的所有系統調用。VFS對用戶提供統一的讀寫接口,用戶調用讀寫等函數時,內核則調用特定的文件系統實現。文件在內核內存中是一個file數據結構來表示的。這個數據結構包含一個f_op的字段,該字段中包含了一組指向特定文件系統實現的函數指針。當用戶執行read()操作時,內核調用sys_read(),然后sys_read()查找到指向該文件屬于的文件系統的讀函數指針,并調用它,即file->f_op->read()。
????????基于VFS實現的文件系統,都必須實現定義這些對象,并實現這些對象中定義的函數指針。
????????cgroup文件系統的定義:
static struct file_system_type cgroup_fs_type = {
????????.name = "cgroup",
????????.get_sb = cgroup_get_sb,
????????.kill_sb = cgroup_kill_sb,
};
????????這里有定義了兩個函數指針,定義了一個文件系統必須實現了的兩個操作get_sb、kill_sb,即獲得超級塊和釋放超級塊。這兩個操作會在使用mount系統調用掛載cgroup文件系統時使用。
參考鏈接?
徹底搞懂容器技術的基石: cgroup
linux 容器(LXC) 第4章 cgroups_caoshuming_500的博客-CSDN博客
Cgroup原理及使用 - zhrx - 博客園
Linux 基礎:cgroup 原理與實現_CGroup_層級_控制
【docker 底層知識】cgroup 原理分析_張忠琳的博客-CSDN博客_cgroup
CGroup的原理和使用_書笑生的博客-CSDN博客_cgroup原理
Docker核心原理之 Cgroup詳解
Linux Cgroups詳解(二) - lisperl - 博客園
Linux Cgroup系列(04):限制cgroup的內存使用(subsystem之memory)
Linux Cgroup系列(04):限制cgroup的內存使用(subsystem之memory) - SegmentFault 思否
Linux Cgroup系列(01):Cgroup概述
Linux Cgroup系列(01):Cgroup概述 - SegmentFault 思否
深入理解 Linux Cgroup 系列(一):基本概念
深入理解 Linux Cgroup 系列(一):基本概念 - SegmentFault 思否
深入理解 Linux Cgroup 系列(二):玩轉 CPU
深入理解 Linux Cgroup 系列(二):玩轉 CPU - SegmentFault 思否
深入理解 Linux Cgroup 系列(三):內存 - SegmentFault 思否
總結
以上是生活随笔為你收集整理的【重识云原生】第六章容器6.1.7.2节——cgroups原理剖析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 史上最强的超级爆笑锦集
- 下一篇: HDU5619 Jam's store(