深刻理解 Linux Cgroup 系列(一):基本概念

原文连接:深刻理解 Linux Cgroup 系列(一):基本概念html

Cgroup 是 Linux kernel 的一项功能:它是在一个系统中运行的层级制进程组,你可对其进行资源分配(如 CPU 时间、系统内存、网络带宽或者这些资源的组合)。经过使用 cgroup,系统管理员在分配、排序、拒绝、管理和监控系统资源等方面,能够进行精细化控制。硬件资源能够在应用程序和用户间智能分配,从而增长总体效率。linux

cgroup 和 namespace 相似,也是将进程进行分组,但它的目的和 namespace 不同,namespace 是为了隔离进程组之间的资源,而 cgroup 是为了对一组进程进行统一的资源监控和限制。segmentfault

cgroup 分 v1v2 两个版本,v1 实现较早,功能比较多,可是因为它里面的功能都是零零散散的实现的,因此规划的不是很好,致使了一些使用和维护上的不便,v2 的出现就是为了解决 v1 中这方面的问题,在最新的 4.5 内核中,cgroup v2 声称已经能够用于生产环境了,但它所支持的功能还颇有限,随着 v2 一块儿引入内核的还有 cgroup namespace。v1 和 v2 能够混合使用,可是这样会更复杂,因此通常没人会这样用。bash

1. 为何须要 cgroup


在 Linux 里,一直以来就有对进程进行分组的概念和需求,好比 session group, progress group 等,后来随着人们对这方面的需求愈来愈多,好比须要追踪一组进程的内存和 IO 使用状况等,因而出现了 cgroup,用来统一将进程进行分组,并在分组的基础上对进程进行监控和资源控制管理等。网络

2. 什么是 cgroup


术语 cgroup 在不一样的上下文中表明不一样的意思,能够指整个 Linux 的 cgroup 技术,也能够指一个具体进程组。session

cgroup 是 Linux 下的一种将进程按组进行管理的机制,在用户层看来,cgroup 技术就是把系统中的全部进程组织成一颗一颗独立的树,每棵树都包含系统的全部进程,树的每一个节点是一个进程组,而每颗树又和一个或者多个 subsystem 关联,树的做用是将进程分组,而 subsystem 的做用就是对这些组进行操做。cgroup 主要包括下面两部分:ssh

  • subsystem : 一个 subsystem 就是一个内核模块,他被关联到一颗 cgroup 树以后,就会在树的每一个节点(进程组)上作具体的操做。subsystem 常常被称做 resource controller,由于它主要被用来调度或者限制每一个进程组的资源,可是这个说法不彻底准确,由于有时咱们将进程分组只是为了作一些监控,观察一下他们的状态,好比 perf_event subsystem。到目前为止,Linux 支持 12 种 subsystem,好比限制 CPU 的使用时间,限制使用的内存,统计 CPU 的使用状况,冻结和恢复一组进程等,后续会对它们一一进行介绍。
  • hierarchy : 一个 hierarchy 能够理解为一棵 cgroup 树,树的每一个节点就是一个进程组,每棵树都会与零到多个 subsystem 关联。在一颗树里面,会包含 Linux 系统中的全部进程,但每一个进程只能属于一个节点(进程组)。系统中能够有不少颗 cgroup 树,每棵树都和不一样的 subsystem 关联,一个进程能够属于多颗树,即一个进程能够属于多个进程组,只是这些进程组和不一样的 subsystem 关联。目前 Linux 支持 12 种 subsystem,若是不考虑不与任何 subsystem 关联的状况(systemd 就属于这种状况),Linux 里面最多能够建 12 颗 cgroup 树,每棵树关联一个 subsystem,固然也能够只建一棵树,而后让这棵树关联全部的 subsystem。当一颗 cgroup 树不和任何 subsystem 关联的时候,意味着这棵树只是将进程进行分组,至于要在分组的基础上作些什么,将由应用程序本身决定,systemd 就是一个这样的例子。

3. 将资源看做一块饼


CentOS 7 系统中(包括 Red Hat Enterprise Linux 7),经过将 cgroup 层级系统与 systemd 单位树捆绑,能够把资源管理设置从进程级别移至应用程序级别。默认状况下,systemd 会自动建立 slicescopeservice 单位的层级(具体的意思稍后再解释),来为 cgroup 树提供统一结构。能够经过 systemctl 命令建立自定义 slice 进一步修改此结构。工具

若是咱们将系统的资源当作一块馅饼,那么全部资源默认会被划分为 3 个 cgroup:System, UserMachine。每个 cgroup 都是一个 slice,每一个 slice 均可以有本身的子 slice,以下图所示:post

下面咱们以 CPU 资源为例,来解释一下上图中出现的一些关键词。性能

如上图所示,系统默认建立了 3 个顶级 sliceSystem, UserMachine),每一个 slice 都会得到相同的 CPU 使用时间(仅在 CPU 繁忙时生效),若是 user.slice 想得到 100% 的 CPU 使用时间,而此时 CPU 比较空闲,那么 user.slice 就可以如愿以偿。这三种顶级 slice 的含义以下:

  • system.slice —— 全部系统 service 的默认位置
  • user.slice —— 全部用户会话的默认位置。每一个用户会话都会在该 slice 下面建立一个子 slice,若是同一个用户屡次登陆该系统,仍然会使用相同的子 slice。
  • machine.slice —— 全部虚拟机和 Linux 容器的默认位置

控制 CPU 资源使用的其中一种方法是 shares。shares 用来设置 CPU 的相对值(你能够理解为权重),而且是针对全部的 CPU(内核),默认值是 1024。所以在上图中,httpd, sshd, crond 和 gdm 的 CPU shares 均为 1024,System, User 和 Machine 的 CPU shares 也是 1024

假设该系统上运行了 4 个 service,登陆了两个用户,还运行了一个虚拟机。同时假设每一个进程都要求使用尽量多的 CPU 资源(每一个进程都很繁忙)。

  • system.slice 会得到 33.333% 的 CPU 使用时间,其中每一个 service 都会从 system.slice 分配的资源中得到 1/4 的 CPU 使用时间,即 8.25% 的 CPU 使用时间。
  • user.slice 会得到 33.333% 的 CPU 使用时间,其中每一个登陆的用户都会得到 16.5% 的 CPU 使用时间。假设有两个用户:tomjack,若是 tom 注销登陆或者杀死该用户会话下的全部进程,jack 就可以使用 33.333% 的 CPU 使用时间。
  • machine.slice 会得到 33.333% 的 CPU 使用时间,若是虚拟机被关闭或处于 idle 状态,那么 system.slice 和 user.slice 就会从这 33.333% 的 CPU 资源里分别得到 50% 的 CPU 资源,而后均分给它们的子 slice。

若是想严格控制 CPU 资源,设置 CPU 资源的使用上限,即无论 CPU 是否繁忙,对 CPU 资源的使用都不能超过这个上限。能够经过如下两个参数来设置:

cpu.cfs_period_us = 统计CPU使用时间的周期,单位是微秒(us) 
cpu.cfs_quota_us = 周期内容许占用的CPU时间(指单核的时间,多核则须要在设置时累加)

systemctl 能够经过 CPUQuota 参数来设置 CPU 资源的使用上限。例如,若是你想将用户 tom 的 CPU 资源使用上限设置为 20%,能够执行如下命令:

$ systemctl set-property user-1000.slice CPUQuota=20%

在使用命令 systemctl set-property 时,可使用 tab 补全:

$ systemctl set-property user-1000.slice
AccuracySec=            CPUAccounting=          Environment=            LimitCPU=               LimitNICE=              LimitSIGPENDING=        SendSIGKILL=
BlockIOAccounting=      CPUQuota=               Group=                  LimitDATA=              LimitNOFILE=            LimitSTACK=             User=
BlockIODeviceWeight=    CPUShares=              KillMode=               LimitFSIZE=             LimitNPROC=             MemoryAccounting=       WakeSystem=
BlockIOReadBandwidth=   DefaultDependencies=    KillSignal=             LimitLOCKS=             LimitRSS=               MemoryLimit=
BlockIOWeight=          DeviceAllow=            LimitAS=                LimitMEMLOCK=           LimitRTPRIO=            Nice=
BlockIOWriteBandwidth=  DevicePolicy=           LimitCORE=              LimitMSGQUEUE=          LimitRTTIME=            SendSIGHUP=

这里有不少属性能够设置,但并非全部的属性都是用来设置 cgroup 的,咱们只须要关注 Block, CPUMemory

若是你想经过配置文件来设置 cgroup,service 能够直接在 /etc/systemd/system/xxx.service.d 目录下面建立相应的配置文件,slice 能够直接在 /run/systemd/system/xxx.slice.d 目录下面建立相应的配置文件。事实上经过 systemctl 命令行工具设置 cgroup 也会写到该目录下的配置文件中:

$ cat /run/systemd/system/user-1000.slice.d/50-CPUQuota.conf
[Slice]
CPUQuota=20%

查看对应的 cgroup 参数:

$ cat /sys/fs/cgroup/cpu,cpuacct/user.slice/user-1000.slice/cpu.cfs_period_us
100000

$ cat /sys/fs/cgroup/cpu,cpuacct/user.slice/user-1000.slice/cpu.cfs_quota_us
20000

这表示用户 tom 在一个使用周期内(100 毫秒)可使用 20 毫秒的 CPU 时间。无论 CPU 是否空闲,该用户使用的 CPU 资源都不会超过这个限制。

CPUQuota 的值能够超过 100%,例如:若是系统的 CPU 是多核,且 CPUQuota 的值为 200%,那么该 slice 就可以使用 2 核的 CPU 时间。

4. 总结


本文主要介绍了 cgroup 的一些基本概念,包括其在 CentOS 系统中的默认设置和控制工具,以 CPU 为例阐述 cgroup 如何对资源进行控制。下一篇文章将会经过具体的示例来观察不一样的 cgroup 设置对性能的影响。

5. 参考资料



相关文章
相关标签/搜索