溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Docker中的cgroup怎么用

發(fā)布時(shí)間:2022-03-03 14:02:17 來(lái)源:億速云 閱讀:188 作者:小新 欄目:開(kāi)發(fā)技術(shù)

小編給大家分享一下Docker中的cgroup怎么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

什么是cgroup

Linux CGroup(Linux Contral Group),它其實(shí)是Linux內(nèi)核的一個(gè)功能,它是Linux下的一種將進(jìn)程按組進(jìn)行管理的機(jī)制。最開(kāi)始是由Google工程師Paul Menage和Rohit Seth于2006年發(fā)起的,最早起名叫進(jìn)程容器。在2007之后隨著容器得提出,為了避免混亂重命名為cgroup,并且被合并到了內(nèi)核2.6.24版本中去了。
在用戶層看來(lái),cgroup技術(shù)就是把系統(tǒng)中的所有進(jìn)程組織成一顆一顆獨(dú)立的樹(shù),每棵樹(shù)都包含系統(tǒng)的所有進(jìn)程,樹(shù)的每個(gè)節(jié)點(diǎn)是一個(gè)進(jìn)程組,而每顆樹(shù)又和一個(gè)或者多個(gè)subsystem關(guān)聯(lián)。樹(shù)主要用來(lái)將進(jìn)程進(jìn)行分組,而subsystem用來(lái)對(duì)這些組進(jìn)行操作。

cgroup的組成

cgroup主要包含以下兩個(gè)部分

  • subsystem: 一個(gè)subsystem就是一個(gè)內(nèi)核模塊,它被關(guān)聯(lián)到一顆cgroup樹(shù)之后,就會(huì)在樹(shù)節(jié)點(diǎn)進(jìn)行具體的操作。subsystem經(jīng)常被稱作"resource controller",因?yàn)樗饕挥脕?lái)調(diào)度或者限制每個(gè)進(jìn)程組的資源,但是這個(gè)說(shuō)法不完全準(zhǔn)確,因?yàn)橛袝r(shí)我們將進(jìn)程分組只是為了做一些監(jiān)控,觀察一下他們的狀態(tài),比如perf_event subsystem。

  • hierarchy:一個(gè)hierarchy可以理解為一棵cgroup樹(shù),樹(shù)的每個(gè)節(jié)點(diǎn)就是一個(gè)進(jìn)程組,每棵樹(shù)都會(huì)與多個(gè)subsystem關(guān)聯(lián)。在一顆樹(shù)里面,會(huì)包含Linux系統(tǒng)中的所有進(jìn)程,但每個(gè)進(jìn)程只能屬于一個(gè)節(jié)點(diǎn)(進(jìn)程組)。系統(tǒng)中可以有很多顆cgroup樹(shù),每棵樹(shù)都和不同的subsystem關(guān)聯(lián),一個(gè)進(jìn)程可以屬于多顆樹(shù),即一個(gè)進(jìn)程可以屬于多個(gè)進(jìn)程組,這些進(jìn)程組和不同的subsystem關(guān)聯(lián)。

可以通過(guò)查看/proc/cgroup目錄查看當(dāng)前系統(tǒng)支持哪些subsystem關(guān)聯(lián)

Docker中的cgroup怎么用

第一列:表示subsystem名

第二列:表示關(guān)聯(lián)到的cgroup樹(shù)的ID,如果多個(gè)subsystem關(guān)聯(lián)到同一顆cgroup樹(shù),那么它們的這個(gè)字段將一樣。比如圖中的cpuset、cpu和cpuacct。

第三列:表示subsystem所關(guān)聯(lián)的cgroup樹(shù)中進(jìn)程組的個(gè)數(shù),即樹(shù)上節(jié)點(diǎn)的個(gè)數(shù)。

cgroup提供的功能

它提供了如下功能

  • Resource limitation:資源使用限制

  • Prioritization:優(yōu)先級(jí)控制

  • Accounting:一些審計(jì)或者統(tǒng)計(jì)

  • Control:掛起進(jìn)程,恢復(fù)執(zhí)行進(jìn)程

一般我們可以用cgroup做以下事情

  • 隔離一個(gè)進(jìn)程集合(比如MySQL的所有進(jìn)程),限定他們所占用的資源,比如綁定的核限制

  • 為這組進(jìn)程分配內(nèi)存

  • 為這組進(jìn)程的分配足夠的帶寬及進(jìn)行存儲(chǔ)限制

  • 限制訪問(wèn)某些設(shè)備

cgroup在Linux中表現(xiàn)為一個(gè)文件系統(tǒng),運(yùn)行如下命令

Docker中的cgroup怎么用

mount成功后,可以看到,在/sys/fs下有個(gè)cgroup目錄,這個(gè)目錄下有很多子系統(tǒng)。比如cpu、cpuset、blkio等。
然后在/sys/fs/cgroup/cpu目錄下建個(gè)子目錄test,這個(gè)時(shí)候會(huì)發(fā)現(xiàn)在該目錄下多了很多文件

Docker中的cgroup怎么用

限制cgroup中的CPU

在cgroup里面,跟CPU相關(guān)的子系統(tǒng)有cpusets、cpuacct和cpu。
其中cpuset主要用于設(shè)置CPU的親和性,可以限制cgroup中的進(jìn)程只能在指定的CPU上運(yùn)行,或者不能在指定的CPU上運(yùn)行,同時(shí)cpuset還能設(shè)置內(nèi)存的親和性。cpuacct包含當(dāng)前cgroup所使用的CPU的統(tǒng)計(jì)信息。這里我們只說(shuō)以下cpu。

然后我們?cè)?sys/fs/cgroup/cpu下創(chuàng)建一個(gè)子group, 該目錄下文件列表

Docker中的cgroup怎么用

cpu.cfs_period_us用來(lái)配置時(shí)間周期長(zhǎng)度,cpu.cfs_quota_us用來(lái)配置當(dāng)前cgroup在設(shè)置的周期長(zhǎng)度內(nèi)所能使用的CPU時(shí)間數(shù),兩個(gè)文件配合起來(lái)設(shè)置CPU的使用上限。兩個(gè)文件的單位都是微秒(us),cpu.cfs_period_us的取值范圍為1毫秒(ms)到1秒(s),cpu.cfs_quota_us的取值大于1ms即可。
下面來(lái)舉個(gè)例子講解如何使用cpu限制
假如我們寫了一個(gè)死循環(huán)

Docker中的cgroup怎么用

運(yùn)行起來(lái)用top查看下占用率達(dá)到了100%

Docker中的cgroup怎么用

我們執(zhí)行如下命令對(duì)cfs_quota_us進(jìn)行設(shè)置

echo 20000 > /sys/fs/cgroup/cpu/test/cpu.cfs_quota_us

這條命令表示把進(jìn)程的CPU利用率下降20%,然后把進(jìn)程PID加入到cgroup中

Docker中的cgroup怎么用

再執(zhí)行top可以看到cpu利用率下降了

Docker中的cgroup怎么用

限制cgroup中的內(nèi)存

代碼如果有bug,比如內(nèi)存泄露等會(huì)榨干系統(tǒng)內(nèi)存,讓其它程序由于分配不了足夠的內(nèi)存而出現(xiàn)異常,如果系統(tǒng)配置了交換分區(qū),會(huì)導(dǎo)致系統(tǒng)大量使用交換分區(qū),從而系統(tǒng)運(yùn)行很慢。
而cgroup對(duì)進(jìn)程內(nèi)存控制主要控制如下:

  • 限制cgroup中所有進(jìn)程使用的內(nèi)存總量

  • 限制cgroup中所有進(jìn)程使用的物理內(nèi)容+swap交換總量

  • 限制cgroup中所有進(jìn)程所能使用的內(nèi)核內(nèi)存總量及其它一些內(nèi)核資源(CONFIG_MEMCG_KMEM)。

這里限制內(nèi)核內(nèi)存就是限制cgroup當(dāng)前所使用的內(nèi)核資源,包括當(dāng)前進(jìn)程的內(nèi)核占空間,socket所占用的內(nèi)存空間等。當(dāng)內(nèi)存吃緊時(shí),可以阻止當(dāng)前cgroup繼續(xù)創(chuàng)建進(jìn)程以及向內(nèi)核申請(qǐng)分配更多的內(nèi)核資源。

下面通過(guò)一個(gè)例子帶大家理解cgroup做內(nèi)存控制的

#include <iostream>
#include <sys/types.h>
#include <cstdlib>
#include <cstdio>
#include <string.h>
#include <unistd.h>

#define CHUNK_SIZE 512


int main()
{
   int size = 0;
   char *p = nullptr; 
   while(1)
   {
          if((p = (char*)malloc(CHUNK_SIZE))==nullptr)
          {
              break;
         }

      memset(p, 0, CHUNK_SIZE);
       printf("[%u]-- [%d]MB is allocated ", getpid(), ++size);
       sleep(1);
   }
    
   return 0;
}

首先,在/sys/fs/cgroup/memory下創(chuàng)建一個(gè)子目錄即創(chuàng)建了一個(gè)子cgroup,比如這里我們創(chuàng)建了一個(gè)test目錄

$mkdir /sys/fs/cgroup/memory/test

test目錄包含以下文件

Docker中的cgroup怎么用

每個(gè)文件的作用大概介紹下:

文件說(shuō)明
cgroup.event_control用于eventfd的接口
memory.usage_in_bytes顯示當(dāng)前已用的內(nèi)存
memory.limit_in_bytes設(shè)置/顯示當(dāng)前限制的內(nèi)存額度
memory.failcnt顯示內(nèi)存使用量達(dá)到限制值的次數(shù)
memory.max_usage_in_bytes歷史內(nèi)存最大使用量
memory.soft_limit_in_bytes設(shè)置/顯示當(dāng)前限制的內(nèi)存軟額度
memory.stat顯示當(dāng)前cgroup的內(nèi)存使用情況
memory.use_hierarchy設(shè)置/顯示是否將子cgroup的內(nèi)存使用情況統(tǒng)計(jì)到當(dāng)前cgroup里面
memory.force_empty觸發(fā)系統(tǒng)立即盡可能的回收當(dāng)前cgroup中可以回收的內(nèi)存
memory.pressure_level設(shè)置內(nèi)存壓力的通知事件,配合cgroup.event_control一起使用
memory.swappiness設(shè)置和顯示當(dāng)前的swappiness
memory.move_charge_at_immigrate設(shè)置當(dāng)進(jìn)程移動(dòng)到其他cgroup中時(shí),它所占用的內(nèi)存是否也隨著移動(dòng)過(guò)去
memory.oom_control設(shè)置/顯示oom controls相關(guān)的配置
memory.numa_stat顯示numa相關(guān)的內(nèi)存

然后通過(guò)寫文件memory.limit_in_bytes來(lái)設(shè)置限額。這里設(shè)置5M的限制,如下圖所示

Docker中的cgroup怎么用

把上面示例進(jìn)程加入這個(gè)cgroup,如下圖所示

Docker中的cgroup怎么用

為了避免受swap空間的影響,設(shè)置swappiness為0來(lái)禁止當(dāng)前cgroup使用swap,如下圖所示

Docker中的cgroup怎么用

當(dāng)物理內(nèi)存達(dá)到上限后,系統(tǒng)的默認(rèn)行為是kill掉cgroup中繼續(xù)申請(qǐng)內(nèi)存的進(jìn)程。那么怎么控制這個(gè)行為呢?那就是配置memory.oom_control。這個(gè)文件里面包含了一個(gè)控制是否為當(dāng)前cgroup啟動(dòng)OOM-killer的標(biāo)識(shí)。如果寫0到這個(gè)文件,將啟動(dòng)OOM-killer,當(dāng)內(nèi)核無(wú)法給進(jìn)程分配足夠的內(nèi)存時(shí),將會(huì)直接kill掉該進(jìn)程;如果寫1到這個(gè)文件,表示不啟動(dòng)OOM-killer,當(dāng)內(nèi)核無(wú)法給進(jìn)程分配足夠的內(nèi)存時(shí),將會(huì)暫停該進(jìn)程直到有空余的內(nèi)存之后再繼續(xù)運(yùn)行;同時(shí),memory.oom_control還包含一個(gè)只讀的under_oom字段,用來(lái)表示當(dāng)前是否已經(jīng)進(jìn)入oom狀態(tài),也即是否有進(jìn)程被暫停了。還有一個(gè)只讀的killed_oom字段,用來(lái)表示當(dāng)前是否有進(jìn)程被kill掉了。

限制cgoup的進(jìn)程數(shù)

cgroup中有一個(gè)subsystem叫pids,功能是限制cgroup及其所有子孫cgroup里面能創(chuàng)建的總的task數(shù)量。這里的task指通過(guò)fork和clone函數(shù)創(chuàng)建的進(jìn)程,由于clone函數(shù)也能創(chuàng)建線程,所以這里的task也包含線程。
之前cgroup樹(shù)是已經(jīng)掛載好的,這里就直接創(chuàng)建子cgroup,取名為test。命令如下圖所示

Docker中的cgroup怎么用

再來(lái)看看test目錄下的文件

Docker中的cgroup怎么用

其中pids.current表示當(dāng)前cgroup和其所有孫子cgroup現(xiàn)有的總的進(jìn)程數(shù)量。

Docker中的cgroup怎么用

pids.max 當(dāng)前cgroup和其所有孫子cgroup所允許創(chuàng)建的最大進(jìn)程數(shù)量。

Docker中的cgroup怎么用

下面我們做個(gè)實(shí)驗(yàn),將pids.max設(shè)置為1

Docker中的cgroup怎么用

然后將當(dāng)前bash進(jìn)程加入到該cgroup中

Docker中的cgroup怎么用

隨便運(yùn)行一個(gè)命令,由于在當(dāng)前窗口pids.current已經(jīng)等于pids.max了,所以創(chuàng)建進(jìn)程失敗

Docker中的cgroup怎么用

當(dāng)前cgroup中的pids.current和pids.max代表了當(dāng)前cgroup及所有子孫cgroup的所有進(jìn)程,所以子孫cgroup中的pids.max大小不能超過(guò)父cgroup中的大小,如果超過(guò)了會(huì)怎么樣?我們把pids.max設(shè)置為3

Docker中的cgroup怎么用

當(dāng)前進(jìn)程數(shù)為2

Docker中的cgroup怎么用

重新打開(kāi)一個(gè)shell窗口,創(chuàng)建個(gè)孫子cgroup,將其中的pids.max設(shè)置為5

Docker中的cgroup怎么用

講當(dāng)前shell的bash進(jìn)程寫入croup.procs

Docker中的cgroup怎么用

回到原來(lái)的shell窗口隨便執(zhí)行一條命令可以看到執(zhí)行失敗

Docker中的cgroup怎么用

可以看到,子cgroup中的進(jìn)程數(shù)不僅受制與自己的pids.max,還受制于祖先cgroup的pids.max

以上是“Docker中的cgroup怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI