前言
cgroups 是Docker的两大核心之一,另一个是namespace ,在讲解网络篇时有提到。cgroups是控制群组,是linux 内核用来限制资源,如内存,磁盘,网络等。
CPU 限制
认识参数
docker 是通过 CPU cgroups 来限制容器使用的cpu上限,而和CPU groups 三个比较重要的参数是: cpu.cfs_quota_us、cpu.cfs_period_us、cpu.shares.
在 linux 中,使用top查看的时候,可以看到几个 %Cpu(s) 开头的这一行
类型 | 说明 |
us | 用户态cpu |
sy | 内核态cpu时间 |
ni | nice 值1-19的进程用户态cpu时间,代表优化级比较低的进程运行占用的时间 |
id | 系统空闲时间 |
wa | iowait,系统等待io的cpu时间 |
hi | hardware irq,处理硬中断时间 |
si | softirq,处理软中断时间 |
st | steal,同一个宿主机上的其他虚拟机抢走的时间 |
从上面可以看出来,cpu时间分成 用户态(us,ni) 与 内核态(sy,wa,hi,si),而内核态中的 wa,hi,si 等这些,cpu groups 不是会进行限制的。
Cgroup 子系统是通过一个虚拟文件挂载点进行管理的,通常是在 /sys/fs/cgroup/cpu 这个目录下。
Linux 通过 CFS(完全公平调度器) 来对调度进程对cpu的使用,默认调度周期是 100ms。影响CFS的有三个参数
- cpu.cfs_period_us ,是CFS 调度的周期,默认是 100000,单位是 microseconds 也就是 100ms
- cpu.cfs_quota_us 在一个调度周期里,这个控制组被允许的运行时间,比如 30000 ,就是 30ms
这两个参数进行除法
cpu.cfs_quota_us/cpu.cfs_period_us ,比如 30ms /100ms = 0.3 ,表示这个控制组被允许使用的CPU最大配额是 0.3个cpu
- cpu.shares 这个值是在 CPU 被占满时,CPU Cgroup 子系统控制组可用CPU的相对比例
这里有一个比较有意思的现象,如果启动两个容器,容器A与容器B,而 A与B的 cpu.shares值分别是1024与512 ,如果B启动后,没有运行任何线程,这时候B自己的 cpu会使用不完,而A 里有很多的线程在跑,这时候就会将容器B的空闲资源占用,也就是CPU是共享的; 后面如果B里也开始跑线程了,就会把自己的资源进行要回来,这时候docker就会按 1024: 512进行划分,也就是 A 会占用 2/3 ,说明cpu是可压缩的资源。
cpu cgroup 数据
查看 cpu的 cgroup 数据,在 /sys/fs/cgroup/cpu下
在目录下有
cgroup.procs 文件,里面当前控制组要控制哪些进程的PID列表
cgroup.cfs_quota_us 这里默认是-1,也就是不限制
当我们创建一个受限制的docker 容器时,会在 /sys/fs/cgroup/cpu/docker下创建一个容器id为名的控制组
启动 docker 时,可以指定参数
-c 或是 --cpu-shares 有多个容器竞争cpu时的比例 (调整 cpu.shares)
--cpus 在docker 1.13 以后,可以限定使用的容器核心数(也就是调整 cpu.cfs_quota_us的值)
也可以通过
--cpu-period、--cpu-quota 分别调整 cpu.cfs_period_us 和 cpu.cfs_quota_us
举例:
进入到对应的控制组里,查看对应的 cgroup.procs 和 cgroup.cfs_quota_us 的值
这些也是当前启动的nginx 容器对应的进程 id,和刚才启动参数里设置的参数 --cpus=0.3的值