概念
- Linux cgroups可以为系统中所运行进程的用户定义组群并分配资源。
- Linux使用namespace隔离与运行环境,然而进程仍然可以不限地使用系统资源(CPU、内存、磁盘等)。占用资源太多会影响其它进程,资源耗尽时会触发OOM
- 对Linux OOM的理解
- Linux内核存在OOM(out of memory)killer机制,通过配置它控制内存不足时内核的行为
- 当物理内存和交换空间都被用完时,如果还有进程来申请内存,内核将触发OOM killer
- 检查文件/proc/sys/vm/panic_on_oom,如果里面的值为2,那么系统一定会触发panic
- 如果/proc/sys/vm/panic_on_oom的值为1,那么系统有可能触发panic
- 如果/proc/sys/vm/panic_on_oom的值为0,或者上一步没有触发panic,那么内核继续检查文件/proc/sys/vm/oom_kill_allocating_task
- 如果/proc/sys/vm/oom_kill_allocating_task为1,那么内核将kill掉当前申请内存的进程
- 如果/proc/sys/vm/oom_kill_allocating_task为0,内核将检查每个进程的分数,分数最高的进程将被kill掉
- 进程被kill掉之后,如果/proc/sys/vm/oom_dump_tasks为1,且系统的rlimit中设置了core文件大小,将会由/proc/sys/kernel/core_pattern里面指定的程序生成core dump文件,这个文件里将包含pid, uid, oom_score_adj,score, name等内容
- Linux OOM如果触发,可能会杀死其它的进程,令系统变得不可控,因此需要使用Linux cgroups来限制容器允许使用的系统资源
- Linux cgroups时以一组进程为目标进行系统资源的分配和控制
功能
- Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制
- Prioritization: 优先级控制,比如:CPU利用和磁盘IO吞吐
- Accounting: 一些审计或一些统计,主要目的是为了计费
- Control: 挂起进程,恢复执行进程
使用cgroup,系统管理员可更具体地控制对系统资源的分配优先顺序、拒绝、管理、监控。可更好地根据任务和用户分配硬件资源,提高总体效率。
在实践中,系统管理员一般会利用CGroup做下面这些事:
- 隔离一个进程集合(比如:nginx的所有进程),并限制他们所消费的资源,比如绑定CPU的核
- 为这组进程分配其足够使用的内存
- 为这组进程分配相应的网络带宽和磁盘存储限制
- 限制访问某些设备(通过设置设备的白名单)
// 检查Linux内核中是否开启了cgroup
cat /boot/config-[kernel-version] |grep CGROUP
Linux将cgroups实现成了文件系统:
/sys/fs/cgroup 目录中有若干个子目录,我们可以认为这些都是受cgroups控制的资源以及这些资源的信息
- blkio — 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等)
- cpu — 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问
- cpuacct — 这个子系统自动生成 cgroup 中任务所使用的 CPU 报告。
- cpuset — 这个子系统为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。
- devices — 这个子系统可允许或者拒绝 cgroup 中的任务访问设备。
- freezer — 这个子系统挂起或者恢复 cgroup 中的任务
- memory — 这个子系统设定 cgroup 中任务使用的内存限制,并自动生成内存资源使用报告。
- net_cls — 这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包
- net_prio — 这个子系统用来设计网络流量的优先级
- hugetlb — 这个子系统主要针对于HugeTLB系统进行限制,这是一个大页文件系统
通过cgroups限制进程
限制cpu
#include<stdio.h>
int main(void) {
int i = 0;
for(;;) i++;
return 0
}
运行以上代码,发现cpu消耗为100%
mkdir /sys/fs/cgroup/cpu/hello
cd /sys/fs/cgroup/cpu/hello
# cpu.cfs_quota_us将时间片分成100000,20000即占用20%cpu,双核系统可以使用200%cpu
ehco 20000 > cpu.cfs_quota_us
echo $PID > tasks
限制memory
mkdir hello
cd hello/
cat memory.limit_in_bytes
echo 64k > memory.limit_in_bytes
echo $PID > tasks
限制进程io
mkdir /sys/fs/cgroup/blkio/io
cd /sys/fs/cgroup/blkio/io
echo '8:0 1048576' > blkio.throttle.read_bps_device
echo $PID > tasks
术语
- 任务tasks
- 系统进程
- 控制组control group
- 一组按照某种标准划分的进程,表示了某进程组。Cgroups中的资源控制都是以控制组为单位实现。一个进程可以加入到某个控制组
- 层级hierarchy
- 控制组可以组织成hierarchical的形式,既一颗控制组的树(目录结构)。控制组树上的子节点继承父结点的属性。简单点说,hierarchy就是在一个或多个子系统上的cgroups目录树
- 子系统subsystem
- 一个子系统就是一个资源控制器,比如CPU子系统就是控制CPU时间分配的一个控制器。子系统必须附加到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制
Docker对cgroups的使用
# 查找docker run对cgroup使用的命令
docker run --help
# 通过命令让docker进程挂起,否则会直接退出
docker run --name alfred --cpu-quota 2500 --cpu-period 1000 --cpu-shares 30 -d ubuntu /bin/sh -c "while true;do echo hello;sleep 5;done"
容器会自动将进程的ID加入到各个资源对应的tasks文件
目前docker已经几乎支持了所有的cgroups资源,可以限制容器对包括network,device,cpu,memory在内的资源的使用