众所周知,Docker中的关键技术就是Namespace和Cgroups。本文将讲述一下linux中的cgroups。
什么是Cgroups
Cgroups是Control Groups的缩写,用来对进程进行资源的限制,控制使用量和统计,包括CPU,内存,存储,网络等等。通过Cgroups,可以很方便地限制某个进程的资源使用率,为容器实现虚拟化提供了基本保障。
官方的定义:
cgroups是linux内核提供的一种机制,这种机器可以根据需求把一些列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。
cgroups是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子对资源进行限制和跟踪。
Cgroups组件
- task(任务):表示系统的一个进程
- cgroups(控制组):cgroups中的资源控制都以cgroup为单位实现,是对进程分组管理的一种机制,可以包含一个或多个子系统(subsystem)。
- subsystem(子系统):资源调度控制器,包括
- blkio:对块设备输入输出的访问控制,(包括磁盘,固态硬盘)
- cpu:设置进程的CPU调度策略
- cpuacct:生成CPU资源使用情况的包括
- devices:控制对设备的访问,开启或关闭
- freezer:挂起或灰度cgroups中的进程
- memory:控制进程的内存使用量
- perf_event:对任务进行统一的性能测试
- net_cls:通过使用等级标识符标记网络数据包,从而允许Linux流量控制程序(TC)区分出来自某个cgroup的包并做限流或监控。
- hierarchy(层级):层级由一系列cgroup以一个树状结构排列而成,每个层级绑定对应的子系统。
组件之间的关系
- 同一层级可以附加一个或多个子系统
- 一个子系统可以附加到多个层级,当且仅当目标层级只有唯一一个子系统。
- 系统每次新建一个层级时,该系统上的所有任务默认加入这个新建层级的初始化cgroup。一个任务不能存在于同一个层级的不同cgroup中,但一个任务可以存在于不同层级中的多个cgroup中。
- 一个进程fork出子进程,子进程和父进程在同一个cgroup中,也可以根据需要将其移动到其他cgroup中。
Kernel接口
以cpu系统为例,看下这个子系统的控制组下的文件
$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cgroup.sane_behavior cpuacct.usage_percpu cpu.rt_period_us cpu.stat release_agent user.slice
cgroup.event_control cpuacct.stat cpu.cfs_period_us cpu.rt_runtime_us docker system.slice
cgroup.procs cpuacct.usage cpu.cfs_quota_us cpu.shares notify_on_release tasks
- tasks:这个文件中记录了在该cgroup中的进程id。
- cgroup.procs:这个文件中记录了该cgroup中的GID。
- notify_on_release:填0或1,表示是否在cgroup中最后一个任务退出时通知运行release agent,默认是0,表示不运行。
- release_agent:指定release agent执行脚本的文件路径,存在于顶级层cgroup目录中,通常用于自动化卸载无用的cgroup。
下面给个例子,限制Pid为223的进程的CPU使用率为20%
## 在cpu子目录下创建控制组
$ sudo mkdir cg1
## 限制223进程
$ echo 223 >> /sys/fs/cgroup/cpu/cg1/tasks
## 限制cpu使用率为20%
$ echo 20000 > /sys/fs/cgroup/cpu/cg1/cpu.cfs_quota_us