简介
在大型系统中,内核资源控制器(称为控制组或 cgroup)在帮助战略应用程序获取所需资源且同时限制其他应用程序使用的资源方面可能特别有用。
|
作为系统管理员,无论您是在大型服务器上整合应用程序还是部署系统以支持云环境中的服务交付,常常需要由您来确保关键负载可以获得它们所需的系统资源。有时,可能需要临时分配资源,例如在会计期末,或者是为了使重要项目能够在严格的截止日期之前如期完成。还有一些其他情况,如应用程序进程很贪婪(声名狼藉的 CPU 或内存消耗大户),有必要限制它们对资源的使用以使其他应用程序不致于得不到资源。
我一直用的是 Oracle Solaris 中的资源控制,因此急于了解在包含 Unbreakable Enterprise Kernel (UEK) 的 Oracle Linux 6 中如何完成同样事情。使用控制组 (cgroup) 进行资源管理只是 Oracle Linux 6 的众多新特性之一。Cgroup 为管理员提供了细粒度的资源分配控制,有助于确保应用程序获得所需资源以提供一致的响应时间和足够的性能。
控制组简介
根据 Linux 内核文档的描述,“控制组提供了一种对任务及其所有未来子任务的集合进行聚合/划分以形成具有特别行为的分层组的机制。”此“行为”由分配系统资源、跟踪使用情况和施加限制的内核子系统(实际资源控制器)定义。分配给每个组的进程将受所定义的资源控制参数集的控制。管理员为每个组分配特定的进程或系统服务,并根据需要调整进程组的资源参数。
在实践中,管理员可以使用 cgroup:
- 隔离资源消耗往往较大的进程集,限制资源使用不高于预先配置的限制
- 为一个或一组应用程序分配足够的内存或处理资源(按特定节点或相对份额)
- 分配网络或存储带宽(I/O 限制)
- 跟踪已分配的资源
- 将设备访问限制为特定用户或组(设备白名单)
注意,有些功能(尤其是 I/O 限制)需要 Oracle Linux 6 UEK 第 2 版内核 (2.6.39) 或者 Oracle Linux 6.1 或更高版本中的 Red Hat 兼容内核。可从 ULN 或从公共 yum 服务器获得 UEK 第 2 版内核 Beta 版。
UEK 第 2 版 Beta 内核包括 Linux 容器 (lxc
),Linux 容器可提供带有自己的进程和网络空间的隔离环境。我将来可能会在另一篇文章中讨论使用 cgroup 和 Linux 容器的主题,在此重点讨论 Oracle Linux 6 中现在提供的基本 cgroup 功能。对于本文中的示例,我将使用 UEK 第 2 版 Beta 版作为起点。务请阅读资源管理指南以及本文末尾提到的其他参考资源以了解有关 cgroup 的更多信息。
应用控制组
在大型服务器上整合多个负载时,cgroup 显得尤其重要,因为您可以用它在不同的负载之间分配资源。例如,假设我想配置 AMP 栈使得 MySQL 服务器进程总共获得两倍于 Apache Web 服务器进程的 CPU 资源。为使用 cgroup 达到此目的,我为一个 cgroup 分配 2 倍的相对处理能力份额,并将所有 mysqld
进程分配到该组,同时为包含 httpd
进程的组只分配一份相对份额(图 1)。
图 1. 可向不同进程组分配 CPU 资源相对份额。
另一种方法,我可以为每个 cgroup 分配特定的 CPU 和内存资源集,如示意图 2 所示。因为 cgroup 可以控制多种资源,所以我可以向同一 cgroup 分配 CPU 和内存并将该 cgroup 与一组给定的进程关联。
图 2. 可以向 cgroup 分配特定资源并将其指定给进程组。
NUMA 固定
对于 NUMA 架构,通过分配特定资源这种方法,可以让进程总是使用固定不变的处理器和内存节点。这可以让处理器访问本地内存而不是非本地内存,因而可以大幅提高性能。
假设我有一个 NUMA 系统,该系统包括两个节点(为简单起见),如下所示:
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 4 8 12 16 20 24 28
node 0 size: 32349 MB
node 0 free: 22057 MB
node 1 cpus: 1 5 9 13 17 21 25 29
node 1 size: 32822 MB
node 1 free: 26766 MB
.
.
.
如图 3 所示,我可以将多个处理器核心分到不同的组中并分配给 AMP 栈的特定进程。这里将处理器核心 0、2、4、6、8、10、12 和 14 分配给 group1-web
以支持一组 Apache httpd
后台程序。将处理器核心 1、3、5、7、9、11、13 和 15 分配给 group2-db
以及关联的mysqld
后台程序。将本地内存节点分别分配给各 cgroup。
图 3. 可以配置 cgroup 以对应 NUMA 节点。
一探究竟
Cgroup 使用基于文件系统的模型来实现 — 正如您可以遍历 /proc
树来查看与进程有关的信息,您可以查看 /cgroup
的层次结构来检查当前控制组层次结构、参数分配和关联任务。
在这个树形文件系统层次结构中,子级继承其父级的属性。该文件系统实现还实现了访问控制 — 每个 cgroup 伪目录有一个所有者和一个组,用来限制哪些人可以修改层次结构及其基础文件,以及哪些进程可以分配给某个 cgroup。
在我举例说明如何配置 cgroup 之前,首先澄清几个术语:
- cgroup 将一组进程或任务与一个或多个子系统的一组参数关联。
- 子系统 是一个资源控制器,它对一组进程应用限制或进行操作。每个子系统有实现资源控制和报告机制的特定参数。
- 层次结构 是一组排列成树形的子系统和 cgroup,使得每个系统进程正好在层次结构中的一个 cgroup 中。
您可以使用 lssubsys
命令(包括在 libcgroup
程序包中)查看可用内核子系统:
# lssubsys -am
cpuset
cpu
cpuacct
memory
devices
freezer
net_cls
blkio
与 Oracle Linux 6 的最初版本 (2.6.32) 相比,UEK 第 2 版添加了 blkio
子系统以实现 I/O 限制。以下是对各种子系统的简要说明(有关每个子系统及其参数的详细信息,请参见资源管理指南):
cpuset
为 cgroup 任务分配各个 CPU 和内存节点cpu
调度 CPU 访问(例如,根据相对份额,如图 1 所示,或针对实时进程)cpuacct
报告所用的总 CPU 时间。memory
报告或限制内存使用。devices
授予或拒绝对设备的访问权限。freezer
挂起或恢复任务。net_cls
使用标识符标记传出网络数据包。blkio
报告或控制块设备的 I/O 带宽。
对于本文中的示例,我将展示如何使用 shell 命令配置非持久性分配,稍后展示如何将这些设置捕获为持久格式。要注意的是(这也是常识!),使用一种技术(如 cgroup)进行可影响内核的修改时,建议您在对生产负载应用更改之前,只在非生产系统上进行动态更改。
我将演示三个示例:
- 使用
cpuset
子系统实现 NUMA 固定 - 设备白名单
- I/O 限制
示例 1:NUMA 固定
为演示如何向一组进程分配 CPU 和内存资源,我将继续假想的 AMP 栈的例子。假设我有一台搭载两个 8 核处理器的物理服务器,我想将 8 个核分配给 Apache Web 服务器,将另外 8 个核分配给 MySQL 数据库,每组都使用一个专用本地内存节点(如图 3 所示)。下面的步骤说明如何对 httpd
和 mysqld
服务器进程进行这些分配。
libcgroup
。
使用 yum list
命令验证在 Oracle Linux 6 上已安装 libcgroup
程序包:
# yum list libcgroup
Loaded plugins: refresh-packagekit
Installed Packages
libcgroup.x86_64 0.37-2.el6 @anaconda-OracleLinuxServer-201105261616.x86_64/6.1
如果未安装 libcgroup
程序包,请使用命令 yum install libcgroup
安装。
有两种办法可以创建层次结构。第一种方法是,首先为层次结构创建一个挂载点,然后使用 mount
命令附加适当的子系统;第二种方法是,使用 cgconfig
服务。在第一种方法中,我使用以下命令创建一个名为 cpu-n-ram
的层次结构并附加 cpu
、cpuset
和 memory
子系统:
# mkdir /cgroup/cpu-n-ram # mount -t cgroup -o cpu,cpuset,memory - /cgroup/cpu-n-ram
创建 cgroup 层次结构的第二种方法是让 cgconfig
服务读取配置文件 /etc/cgconfig.conf
。此文件中该挂载的对等项如下所示:
mount { cpuset = /cgroup/cpu-n-ram; cpu = /cgroup/cpu-n-ram; memory = /cgroup/cpu-n-ram; }
重新启动 cgconfig
服务将读取该配置文件并创建 /cgroup/cpu-n-ram
层次结构:
# service cgconfig restart
对于这两种方法,可以使用以下命令确认挂载是否成功:
# mount | grep cgroup
cpu-n-ram on /cgroup/cpu-n-ram type cgroup (rw,cpu,cpuset,memory)
挂载的结果是,使用指定子系统的参数项填充了该层次结构,如清单 1 所示。
清单 1. 使用参数项填充层次结构# ls /cgroup/cpu-n-ram
cgroup.procs memory.failcnt
cpu.rt_period_us memory.force_empty
cpu.rt_runtime_us memory.limit_in_bytes
cpuset.cpu_exclusive memory.max_usage_in_bytes
cpuset.cpus memory.memsw.failcnt
cpuset.mem_exclusive memory.memsw.limit_in_bytes
cpuset.mem_hardwall memory.memsw.max_usage_in_bytes
cpuset.memory_migrate memory.memsw.usage_in_bytes
cpuset.memory_pressure memory.soft_limit_in_bytes
cpuset.memory_pressure_enabled memory.stat
cpuset.memory_spread_page memory.swappiness
cpuset.memory_spread_slab memory.usage_in_bytes
cpuset.mems memory.use_hierarchy
cpuset.sched_load_balance notify_on_release
cpuset.sched_relax_domain_level release_agent
cpu.shares tasks
子系统参数是 cgroup 资源控制的核心 — 它们本质上来说就像是旋钮,通过旋转这些旋钮,您可以为每个子系统设置限制、限制访问或定义分配。了解具体参数将有助于您了解使用 cgroup 控制资源的种种可能性。tasks
文件(清单 1 输出中的最后一行)跟踪由参数设置控制的层次结构所关联的进程。一旦设置完成(在下面的第 5 步之后),tasks
文件将包含为 cgroup 分配的所有进程 ID (PID)。
cgcreate
)。
以下 cgcreate
命令将创建名为 group1-web
和 group2-db
的 cgroup:
# cgcreate -g cpuset:/group1-web # cgcreate -g cpuset:/group2-db
注意,您可以使用用户和组所有权控制哪些人有权在该层次结构中创建 cgroup。相应语法如下,其中 -t <uid:gid>
指定允许向 cgroup 分配任务的用户和组 ID,-a <uid:gid>
指定允许管理 cgroup 和更改子系统参数的用户和组 ID:
cgcreate -t <uid:gid> -a <uid:gid> -g <subsystems:cgroup-path>
自主访问控制 (DAC) 机制应用于代表 cgroup 和子系统参数的目录和文件,从而对 cgroup 更改进行限制,只允许授权用户和组进行 cgroup 更改。
第 4 步:设置 cgroup 的子系统参数 (cgset
)。
以下 cgset
命令设置 group1-web
和 group2-db
cgroup 的参数,即分配 CPU 和内存节点:
# cgset -r cpuset.cpus='0,2,4,6,8,10,12,14' group1-web # cgset -r cpuset.cpus='1,3,5,7,9,11,13,15' group2-db # cgset -r cpuset.mems='0' group1-web # cgset -r cpuset.mems='1' group2-db
重要提示:如果您在 cgroup 定义中使用 cpuset
子系统,则参数 cpuset.cpus
和 cpuset.mems
是必需的参数,必须对它们进行定义。资源管理指南中记载了所有内核子系统参数。
有几种办法可以为 cgroup 分配一个或一组进程,以便由关联资源控制来管理这些进程。cgclassify
命令将一个现有进程移到 cgroup 中:
# cgclassify -g cpuset:group1-web 1683
这与在 tasks
文件中放入 PID 1683 有着同样的效果:
# echo 1683 > /cgroup/cpu-n-ram/group1-web/tasks
一个进程的子进程将继承其父进程的 cgroup,因此可以使用“基础”进程以便后续子进程(分解、执行或克隆的)具有与父进程相同的 cgroup。下面用一个简单的办法来说明这一概念,将当前 shell 附加到 cgroup,如下所示:
# echo $$ > /cgroup/cgroup-name/tasks
该 shell 中后续启动的任何进程将自动分配到该 shell 的 cgroup。
或者,还可以使用 cgexec
命令在指定 cgroup 中启动一个进程:
# cgexec -g cpuset:group1-web httpd
对于 /etc/sysconfig
中有配置文件的服务,可以编辑该配置文件以将该服务自动分配到 cgroup。例如,在 /etc/sysconfig/httpd
中添加下面这行代码:
CGROUP_DAEMON="cpuset:group1-web"
然后启动该服务以自动在指定 cgroup 中执行相应进程:
# service httpd start
我们还可以通过设置规则来让 cgred
(cgroup 规则引擎后台程序)自动将进程分配给特定组。cgred
后台程序根据 /etc/cgrules.conf
文件中的设置将任务移到 cgroup 中。有关详细信息,请参见文档。
一旦将进程分配到 cgroup,内核将在设置的资源分配内执行这些任务。在 AMP 进程的示例中,我未给 httpd
和 mysqld
进程指定访问其各自 CPU 和内存资源的独占权限。如果其他进程需要这些资源且 CPU/内存节点可用,它们仍可使用这些已分配的资源来运行。但还有两个参数(cpuset.cpu_exclusive
和 cpuset.mem_exclusive
)可以更改此默认行为并授予独占访问权限。
代替 cpuset
子系统的是,我可以使用其他子系统限制 httpd
和 mysqld
进程的 CPU 和内存使用。例如,如果我想让 mysqld
进程组 (group2-db
) 合计拥有两倍于 httpd
进程 cgroup (group1-web
) 的总 CPU 时间,我可以为 cgroup1-web
设置 cpu.shares=1
,并为cgroup2-db
设置 cpu.shares=2
,这样就可以为数据库服务器提供两倍的相对 CPU 时间。我还可以使用 memory
子系统参数为 cgroup 设置内存限制。参数 memory.limit_in_bytes
限制 cgroup 中进程的最大用户内存量,而 memory.memsw.limit_in_bytes
同时限制用户内存和交换空间。
示例 2:设备白名单
devices 子系统提供细粒度的系统设备控制。管理员可以定义对特定设备的访问进行限制的 cgroup,并定义哪些用户或组可以访问这些设备,从而增强安全性和数据保护。我将逐步介绍一个示例。
第 1 步:创建 cgroup 并附加子系统。首先我将创建一个层次结构并附加 devices 子系统:
# mkdir /cgroup/devtest # mount -t cgroup -o devices - /cgroup/devtest
这将在层次结构中填充代表子系统参数的伪文件:
# ls -l /cgroup/devtest
total 0
-rw-r--r--. 1 root root 0 Jan 16 09:45 cgroup.clone_children
--w--w--w-. 1 root root 0 Jan 16 09:45 cgroup.event_control
-rw-r--r--. 1 root root 0 Jan 16 09:45 cgroup.procs
--w-------. 1 root root 0 Jan 16 09:45 devices.allow
--w-------. 1 root root 0 Jan 16 09:45 devices.deny
-r--r--r--. 1 root root 0 Jan 16 09:45 devices.list
-rw-r--r--. 1 root root 0 Jan 16 09:45 notify_on_release
-rw-r--r--. 1 root root 0 Jan 16 09:45 release_agent
-rw-r--r--. 1 root root 0 Jan 16 09:45 tasks
第 2 步:创建 cgroup (
cgcreate
)。
以下 cgcreate
命令创建 group3-dev
cgroup:
# cgcreate -g devices:/group3-dev
第 3 步:设置子系统参数 (
cgset
)。
对于本例,我将控制对首个硬盘驱动器 /dev/sda
的访问。为确定 /dev/sda
的主次设备号,我查看设备节点:
# ls -l /dev/sda
brw-rw---- 1 root disk 8, 0 Jan 16 09:24 /dev/sda
根据 ls
的输出结果,/dev/sda
的主设备号为 8,次设备号为 0。以下 cgset
命令设置拒绝对 /dev/sda
进行访问的参数:
# cgset -r devices.deny='b 8:0 mrw' group3-dev
b
指示块设备,但我也可以同时限制对块设备和字符设备的访问。块设备(如硬盘、闪存驱动器和 CDROM)以缓冲块方式移动数据,不同于逐字符传输数据的字符设备(如键盘、鼠标和串行设备)。
我将向 cgroup 附加当前 shell,以便该 shell 及任何后续命令可以自动分配给 cgroup group3-dev
的 tasks 伪文件:
# echo $$ > /cgroup/devtest/group3-dev/tasks
第 5 步:测试设备访问。
此时,我仍可以访问 inode 并查看该设备是否存在:
# file /dev/sda
/dev/sda: block special
但即使我是 root,我也不能从该设备读取数据或意外运行 fdisk
:
# dd if=/dev/sda bs=512 count=1 dd: opening `/dev/sda': Operation not permitted # fdisk /dev/sda Unable to open /dev/sda
为允许访问,我更改了子系统参数 devices.allow
:
# cgset -r devices.allow='b 8:0 mrw' group3-dev
现在我可以从该设备读取数据:
# dd if=/dev/sda of=/dev/null bs=512 count=1
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000514591 seconds, 995 kB/s
devices 子系统旨在限制或允许对设备的访问,以提供一种细粒度的数据保护方式。
示例 3:I/O 限制
devices 子系统控制或拒绝设备访问,而 blkio
子系统限制对指定块设备的 I/O 操作,如下例所示。
对于分配给 blkio
子系统的进程,我们可以通过两种方式控制它们对块设备的 I/O 操作:
- 通过加权系数。
blkio
子系统参数 (blkio.weight
) 允许每个 cgroup 拥有相对份额的可用 I/O。加权机制在完全公平队列 I/O 调度器中实现。(有关详细信息,请参见文档。) - 通过 I/O 限制。可以使用子系统参数来为块设备设置 I/O 操作数上限。这提供了一种限制分配到 cgroup 的进程的读/写速率的手段。
在本示例中,我将对一些进程配置限制功能,限制硬盘设备 /dev/sda
的 I/O 带宽(字节/秒)。然后我将展示如何为从该设备读取数据的 cgroup 进程设置每秒 I/O 操作数上限。
限制带宽
第 1 步:创建 cgroup 并附加子系统。首先确保已挂载 blkio
控制器:
# grep blkio /proc/mounts || mkdir /cgroup/blkio ; mount -t cgroup -o blkio none /cgroup/blkio
第 2 步:创建 cgroup (
cgcreate
)。
然后创建一个名为 io-test
的 cgroup:
# cgcreate -g blkio:/io-test
第 3 步:为 cgroup 分配进程。
我将当前 shell 分配到此 cgroup,以便 blkio
控制器管理在该 shell 内执行的每一条后续命令的 I/O:
# echo $$ > /cgroup/blkio/io-test/tasks
第 4 步:设置子系统参数。
我希望指定一个带宽速率以限制该 cgroup 中的所有进程对驱动器 /dev/sda
的 I/O。首先使用 hdparm -t
检查设备的未设限读取性能:
# hdparm --direct -t /dev/sda
/dev/sda:
Timing O_DIRECT disk reads: 350 MB in 3.00 seconds = 116.61 MB/sec
为了建立带宽上限,我需要设置子系统参数 blkio.throttle.read_bps_device
。其格式为 <major>:<minor> <bytes_per_second>
。同样,查看设备节点以获取主设备号和次设备号:
# ls -l /dev/sda
brw-rw---- 1 root disk 8, 0 Jan 16 10:01 /dev/sda
现在对源于此设备的读取操作设置 1 MB/秒(1024x1024 字节)的限制:
# echo "8:0 1048576" > /cgroup/blkio/io-test/blkio.throttle.read_bps_device
或者,也可以使用 cgset
命令:
# cgset -r blkio.throttle.read_bps_device="8:0 1048576" io-test
再次检查读取性能:
# hdparm --direct -t /dev/sda
/dev/sda:
Timing O_DIRECT disk reads: 4 MB in 4.00 seconds = 1.00 MB/sec
整体吞吐量现在限制为指定的速率。
可以通过将 blkio.throttle.read_bps_device
设置为 0 取消带宽限制:
# echo "8:0 0" > blkio.throttle.read_bps_device
也可以使用以下方法:
# cgset -r blkio.throttle.read_bps_device="8:0 0" io-test
如果重新检查吞吐量,会发现速率已经回到先前的未设限状态:
# hdparm --direct -t /dev/sda
/dev/sda:
Timing O_DIRECT disk reads: 352 MB in 3.00 seconds = 117.17 MB/sec
可以按类似方式,通过在 blkio.throttle.write_bps_device
文件中写入每秒字节数来配置写入限制。
限制 IOPS
作为对限制整体带宽的替代方法,还可以限制设备的每秒最大 I/O 操作数 (IOPS)。我将使用 iostat
测量设备的未设限 IOPS(iostat
是sysstat
程序包的一部分),并将使用 hdparm
生成一些磁盘负载。
在另一个 shell(如另一个终端窗口)中运行 iostat
命令:
# iostat 1 -d /dev/sda
输出每秒更新一次,汇总该驱动器的 IOPS 数。在“基础”窗口中,运行 hdparm
命令(具体为 hdparm --direct -t /dev/sda
)并观察iostat
的每秒事务值 (tps
) 如何变化:
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 31.00 15872.00 0.00 15872 0 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 235.00 120320.00 0.00 120320 0 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 240.00 122880.00 0.00 122880 0
注意 tps
如何从空闲模式时的 31 跳到 hdparm
运行时的 230 以上。为将设备 /dev/sda
的 IOPS 速率限制为 50,我返回“基础”窗口并设置blkio
子系统参数以限制读取 IOPS:
# echo "8:0 50" > /cgroup/blkio/io-test/blkio.throttle.read_iops_device
再次运行 hdparm
测试并观察 iostat
输出中的受限每秒事务值:
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 0.00 0.00 0.00 0 0 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 10.00 5120.00 0.00 5120 0 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 50.00 25600.00 0.00 25600 0 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 50.00 25600.00 0.00 25600 0
可以轻松查看 blkio
资源控制器如何执行作业,将最高 IOPS 速率限制为 50。因此,由 hdparm
测量的吞吐量也将下降。
为禁用基于 IOPS 的 I/O 限制,再次将子系统参数的值设置为 0:
# echo "8:0 0" > /cgroup/blkio/io-test/blkio.throttle.read_iops_device
使用 blkio
控制器为您提供了一种灵活的工具来限制进程组的磁盘 I/O 使用,允许您通过明确定义带宽和吞吐量的上限来建立服务级别协议。
捕获参数
到目前为止,我在命令行所作的所有操作在重新启动后都将失效。一旦设置层次结构、附加 cgroup 并按照我需要的方式定义参数,就可以使用 cgsnapshot
捕获现有配置:
# cgsnapshot -s > cgconfig-example.conf
清单 2 显示捕获的配置。
清单 2.cgsnapshot
输出
# Configuration file generated by cgsnapshot mount { cpuset = /cgroup/cpu-n-ram; cpu = /cgroup/cpu-n-ram; memory = /cgroup/cpu-n-ram; devices = /cgroup/devtest; blkio = /cgroup/blkio; } group group2-db { cpuset { cpuset.memory_spread_slab="0"; cpuset.memory_spread_page="0"; cpuset.memory_migrate="0"; cpuset.sched_relax_domain_level="-1"; cpuset.sched_load_balance="1"; cpuset.mem_hardwall="0"; cpuset.mem_exclusive="0"; cpuset.cpu_exclusive="0"; cpuset.mems="1"; cpuset.cpus="1,3,5,7,9,11,13,15"; } cpu { cpu.rt_period_us="1000000"; cpu.rt_runtime_us="0"; } memory { memory.memsw.failcnt="0"; memory.memsw.limit_in_bytes="9223372036854775807"; memory.memsw.max_usage_in_bytes="0"; memory.swappiness="60"; memory.use_hierarchy="0"; memory.failcnt="0"; memory.soft_limit_in_bytes="9223372036854775807"; memory.limit_in_bytes="9223372036854775807"; memory.max_usage_in_bytes="0"; } } group group1-web { cpuset { cpuset.memory_spread_slab="0"; cpuset.memory_spread_page="0"; cpuset.memory_migrate="0"; cpuset.sched_relax_domain_level="-1"; cpuset.sched_load_balance="1"; cpuset.mem_hardwall="0"; cpuset.mem_exclusive="0"; cpuset.cpu_exclusive="0"; cpuset.mems="0"; cpuset.cpus="0,2,4,6,8,10,12,14"; } cpu { cpu.rt_period_us="1000000"; cpu.rt_runtime_us="0"; } memory { memory.memsw.failcnt="0"; memory.memsw.limit_in_bytes="9223372036854775807"; memory.memsw.max_usage_in_bytes="7303168"; memory.swappiness="60"; memory.use_hierarchy="0"; memory.failcnt="0"; memory.soft_limit_in_bytes="9223372036854775807"; memory.limit_in_bytes="9223372036854775807"; memory.max_usage_in_bytes="7303168"; } } group group3-dev { devices { devices.deny="a *:* rwm"; devices.allow="b 8:0 rwm"; } } group io-test { blkio { blkio.throttle.write_iops_device=""; blkio.throttle.read_iops_device=""; blkio.throttle.write_bps_device=""; blkio.throttle.read_bps_device=""; blkio.reset_stats=""; blkio.weight="500"; blkio.weight_device=""; } }
Cgroup 作为服务来实现,它在引导时读取配置文件 /etc/cgconfig.conf
以填充 cgroup 层次结构。为使 cgroup 定义和分配在重新启动后保持有效,可以编辑默认配置文件(插入捕获的子系统挂载、cgroup 定义和参数规范,如清单 2 所示),然后重新启动 cgconfig
服务:
# service cgconfig restart
一旦重新启动 cgconfig
服务,即可将进程分配到定义的 cgroup,或使用 cgred
后台程序根据创建的规则分配进程。
总结
本文只是浅尝辄止地探讨了 cgroup 可能的用途。很容易就可以看出此特性将如何与 Linux 容器集成 — 管理员将能够通过精确控制 CPU、内存和 I/O 资源来创建用户空间操作环境,这十分适用于整合。我期待着未来围绕 cgroup 和 Oracle Linux 6 UEK 第 2 版的开发。
资源
以下是本文前面所引用的资源:
- 内核文档:http://www.kernel.org/doc/Documentation/cgroups/cgroups.txt
- ULN:http://linux.oracle.com/
- 公共 yum 服务器:http://public-yum.oracle.com/beta/
- 资源管理指南:http://linux.oracle.com/documentation/EL6/Red_Hat_Enterprise_Linux-6-Resource_Management_Guide-en-US.pdf
下面是其他一些资源:
- 关于 cgroup 的 Wikipedia 条目:http://en.wikipedia.org/wiki/Cgroups
libcgroup
手册页面- Oracle Linux 6 文档:http://linux.oracle.com/documentation/
- Oracle 技术网 Linux 站点:http://www.oracle.com/technetwork/cn/server-storage/linux/whatsnew/index.html
- Twitter 上的 @ORCL_Linux:http://twitter.com/ORCL_Linux
- Facebook 上的 Oracle Linux:http://www.facebook.com/OracleLinux