Linux资源控制-CPU和内存

本文介绍了如何在Linux系统中使用cgroup控制进程的CPU和内存资源,包括修改调度策略、实时进程CPU控制及内存使用限制等实践操作。

主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。

 

CPU资源控制

每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.

Linux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的.

Linux的调度策略可以参见代码: include/linux/sched.h

复制代码
/*
 * Scheduling policies
 */
#define SCHED_NORMAL        0
#define SCHED_FIFO        1
#define SCHED_RR        2
#define SCHED_BATCH        3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE        5
/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
#define SCHED_RESET_ON_FORK     0x40000000
复制代码

 

Linux 系统也提供了修改调度策略的命令和系统调用接口.

调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.

复制代码
# 在一个终端中执行
sleep 1000
# 打开另一个终端
ps -ef | grep sleep  # 找出 sleep 1000 的pid, 这里假设是 1234
chrt -p 1234         # 可以查看 pid=1234 的进程的 调度策略, 输入如下:
      pid 1234's current scheduling policy: SCHED_OTHER
      pid 1234's current scheduling priority: 0

chrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10
chrt -p 1234         # 再次查看调度策略
      pid 1234's current scheduling policy: SCHED_FIFO
      pid 1234's current scheduling priority: 10
复制代码

 

补充:

  1. chrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help
  2. 查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<PID>/sched

 

实时进程的CPU控制

所谓的实时进程, 也就是那些对响应时间要求比较高的进程.

这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断.

在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.

因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的.

 

所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.

 

系统整体设置

1. 获取当前系统的设置

sysctl -n kernel.sched_rt_period_us   # 实时进程调度的单位CPU时间 11000000
sysctl -n kernel.sched_rt_runtime_us  # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒
950000

这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.

这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.

 

2. 设置实时进程占用CPU时间

上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:

sysctl -w kernel.sched_rt_runtime_us=900000    # 设置实时进程每1秒中只占0.9秒的CPU时间
kernel.sched_rt_runtime_us = 900000
sysctl -n kernel.sched_rt_runtime_us 
900000

 

cgroup 中的设置

整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制.

如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y

查看当前系统的内核编译选项方法如下: (debian 7.6 系统)

cat /boot/config-`uname -r`

查看 CONFIG_RT_GROUP_SCHED 是否启用

cat /boot/config-`uname -r` | grep -i rt_group
# CONFIG_RT_GROUP_SCHED is not set

debian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件

复制代码
mkdir /mnt/cgroup
mount -t cgroup cgroup /mnt/cgroup/
cd /mnt/cgroup/
ls -l
total 0
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time
--w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time
-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight
-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device
-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
--w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control
-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares
--w------- 1 root root 0 Aug 28 09:06 devices.allow
--w------- 1 root root 0 Aug 28 09:06 devices.deny
-r--r--r-- 1 root root 0 Aug 28 09:06 devices.list
-rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid
-rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release
-rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
-rw-r--r-- 1 root root 0 Aug 28 09:06 tasks
复制代码

 

果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us

没办法, 重新编译内核, 编译内核的具体方法参见:  编译Linux内核

为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y

下载源码等等参见: 编译Linux内核, 主要步骤如下:

复制代码
cd /path/to/linux-source-3.2
make localmodconfig
vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
make
make modules_install
make install
reboot      # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核
复制代码
 

启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用

cat /boot/config-`uname -r` | grep -i rt_group
CONFIG_RT_GROUP_SCHED=y       # 已启用

 

再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us

复制代码
mount -t cgroup cgroup /mnt/cgroup/
cd /mnt/cgroup/
ls -l
total 0
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time
--w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device
-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children
--w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control
-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs
-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage
-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate
-r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares
--w------- 1 root root 0 Aug 28 09:53 devices.allow
--w------- 1 root root 0 Aug 28 09:53 devices.deny
-r--r--r-- 1 root root 0 Aug 28 09:53 devices.list
-rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid
-rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release
-rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent
-rw-r--r-- 1 root root 0 Aug 28 09:53 tasks

cat cpu.rt_period_us 
1000000
cat cpu.rt_runtime_us 
950000
复制代码

 

通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.

 

资源控制实例

上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.

Linux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory

 

实例: cgroup 中对其中 *子cgroup* 的CPU资源控制

对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件

直接用实验过程来说话, 其中加入了一些注释.

# 安装需要的软件
apt-get install stress     # 让CPU达到 100% 的压力工具
apt-get install sysstat    # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具

 

实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2
  1. 挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)
  2. 在 cgroup中创建 2个子cgroup A 和 B
  3. 默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 1024
  4. 在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%
  5. top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)

 

复制代码
# 挂载 cgroup 文件系统
mount -t cgroup -o cpu cgroup /mnt/cgroup/
cd /mnt/cgroup
ls -l
total 0
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time
--w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device
-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
--w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control
-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares
--w------- 1 root root 0 Aug 28 11:29 devices.allow
--w------- 1 root root 0 Aug 28 11:29 devices.deny
-r--r--r-- 1 root root 0 Aug 28 11:29 devices.list
-rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid
-rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release
-rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent
-rw-r--r-- 1 root root 0 Aug 28 11:29 tasks

# 创建 子cgroup A 和 B
mkdir {A,B}
cat A/cpu.shares 
1024
cat B/cpu.shares 
1024

# 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%
echo $$ > A/tasks  # 将当前的 SHELL 加入到 cgroup A中
stress -c 2    # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
# 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中
echo $$ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
stress -c 2    # 在2个核上都产生 100% 的CPU 占用率
# 再打开一个 shell 窗口, 用top命令查看 CPU占用情况
top
top - 14:10:32 up 43 min,  3 users,  load average: 2.31, 1.24, 0.62
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   1887872 total,   114744 used,  1773128 free,    10472 buffers
KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached

 PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
3350 root      20   0  6524   92    0 R  49.9  0.0   0:08.73 stress                                                                                                                       
3351 root      20   0  6524   92    0 R  49.9  0.0   0:08.67 stress                                                                                                                       
3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
3354 root      20   0  6524   92    0 R  49.9  0.0   0:07.36 stress                    

# 查看这 4 个stress 进程是否分别属于 A 和 B
cat /mnt/cgroup/A/tasks 
2945
3349
3350   <-- stress 进程
3351   <-- stress 进程
cat /mnt/cgroup/B/tasks 
2996
3352
3353   <-- stress 进程
3354   <-- stress 进程
复制代码

可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,

由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/2

 

实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3
  1. 环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B
  2. A group 的 cpu.shares 文件不变, 值为 1024
  3. B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512+1024) = 1/3)
  4. 同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况

 

复制代码
# 在 B 中shell 窗口执行以下命令
cat B/cpu.shares 
1024
echo 512 > B/cpu.shares 
cat B/cpu.shares 
512
stress -c 2

# 在 A 中 shell 窗口执行以下命令
stress -c 2

# 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况
top
top - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.01
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   1887872 total,   114744 used,  1773128 free,    10488 buffers
KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached

 PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
3376 root      20   0  6524   88    0 R  66.6  0.0   0:06.29 stress                                                                                                                       
3377 root      20   0  6524   88    0 R  66.6  0.0   0:06.30 stress                                                                                                                       
3373 root      20   0  6524   88    0 R  33.3  0.0   0:04.33 stress                                                                                                                       
3374 root      20   0  6524   88    0 R  33.3  0.0   0:04.32 stress               

# 查看这 4 个stress 进程是否分别属于 A 和 B
cat /mnt/cgroup/A/tasks 
2945
3375
3376    <-- stress 进程
3377    <-- stress 进程
cat /mnt/cgroup/B/tasks 
2996
3372
3373    <-- stress 进程
3374    <-- stress 进程
复制代码

很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.

 

实例3 - 物理CPU的控制

上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.

要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.

首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y

cat /boot/config-`uname -r` | grep -i cpusets
CONFIG_CPUSETS=y

我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......

 

然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况

  1. 卸载当前的 cgroup
  2. 再次挂载 cgroup 文件系统, 并指定 -o cpuset
  3. 指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1)
  4. 指定 B 的物理CPU也为 0
  5. 重复 实例1 中的步骤, 观察发生的变化

 

复制代码
umount /mnt/cgroup
mount -t cgroup -o cpuset cgroup /mnt/cgroup/
cd /mnt/cgroup
ls -l
total 0
-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children
--w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus    <-- 这个就是设置关联物理CPU的文件
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate
-r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release
-rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent
-rw-r--r-- 1 root root 0 Aug 28 14:39 tasks

# 创建子cgroup A 和 B
mkdir {A,B}
cat A/cpuset.cpus   
         <--  默认是空的
echo 0 > A/cpuset.cpus
cat A/cpuset.cpus 
0
echo 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU0
# 当前Shell加入到 A组
echo $$ > /mnt/cgroup/A/tasks 
-bash: echo: write error: No space left on device
复制代码

 

如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: http://serverfault.com/questions/579555/cgroup-no-space-left-on-device)

复制代码
# 同时设置 A 的 cpuset.cpus 和 cpuset.mems
echo 0 > A/cpuset.cpus
echo 0 > A/cpuset.mems
# B组也同样设置
echo 0 > B/cpuset.cpus
echo 0 > B/cpuset.mems

# 将当前 shell 加入到 A组
echo $$ > /mnt/cgroup/A/tasks   <-- 设置过 cpuset.mems 后, 就没有出错了
stress -c 2

# 再打开一个Shell窗口, 并加入到 B组
echo $$ > /mnt/cgroup/B/tasks
stress -c 2

# 再打开第3个 shell 窗口, 用top命令查看CPU使用情况
top
top - 15:13:29 up  1:46,  3 users,  load average: 1.01, 0.24, 0.12
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
%Cpu(s): 50.0 us,  0.0 sy,  0.0 ni, 50.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers
KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached

 PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
3830 root      20   0  6524   92    0 R  25.0  0.0   0:04.96 stress                                                                                                                       
3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       
3834 root      20   0  6524   92    0 R  25.0  0.0   0:03.56 stress                                                                                                                       
3833 root      20   0  6524   92    0 R  24.6  0.0   0:03.56 stress
复制代码

从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,

所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.

 

如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.

下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样.

复制代码
# 在 B组的 shell 窗口中执行以下命令
echo 1 > /mnt/cgroup/B/cpuset.cpus
cat /mnt/cgroup/B/cpuset.cpus
1
stress -c 2

# 在 A组的 shell 窗口中执行以下命令
stress -c 2

# 在第3个shell窗口中用top命令查看执行结果
top
top - 15:20:07 up  1:53,  3 users,  load average: 0.38, 0.83, 0.56
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   1887872 total,   117340 used,  1770532 free,    11168 buffers
KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
 3854 root      20   0  6524   88    0 R  49.9  0.0   0:03.76 stress                                                                                                                       
 3857 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
 3858 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
 3855 root      20   0  6524   88    0 R  49.6  0.0   0:03.76 stress
复制代码

果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.

 

实例4 - cgroup 对使用的内存的控制

cgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory

# 首先之前挂载的 cpuset 子系统
umount /mnt/cgroup

# 挂载cgroup 文件系统, 指定 -o memeory
mount -o memory -t cgroup memcg /mnt/cgroup/
mount: special device memcg does not exist

 

出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:

复制代码
cat /proc/cgroups 
#subsys_name    hierarchy    num_cgroups    enabled
cpuset    0    1    1
cpu    0    1    1
cpuacct    0    1    1
memory    1    1    0              <-- 这里的 enabled 是 0
devices    0    1    1
freezer    0    1    1
net_cls    0    1    1
blkio    0    1    1
perf_event    0    1    1
复制代码

 

为了默认启用memory子系统, 可以设置 grub选项

vim /etc/default/grub
# 修改 GRUB_CMDLINE_LINUX=""  ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory"
# 保存后, 更新grub.cfg
update-grub
reboot

 

重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了

复制代码
cat /proc/cgroups 
#subsys_name    hierarchy    num_cgroups    enabled
cpuset    0    1    1
cpu    0    1    1
cpuacct    0    1    1
memory    1    1    1
devices    0    1    1
freezer    0    1    1
net_cls    0    1    1
blkio    0    1    1
perf_event    0    1    1

# 挂载cgroup 的memory子系统
mount -t cgroup -o memory memcg /mnt/cgroup
ls -l /mnt/cgroup/   <-- 可以看到有很多 memory 相关的配置
total 0
-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children
--w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control
-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt
--w------- 1 root root 0 Aug 28 15:54 memory.force_empty
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes   <-- 限制内存使用的配置文件
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
-rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release
-rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
-rw-r--r-- 1 root root 0 Aug 28 15:54 tasks
复制代码

 

开始实验:

  1. 重启系统 (为了保证内存的干净)
  2. 挂载 memcg
  3. 在挂载的 /mnt/cgroup 中创建 组A
  4. 将当前shell 加入到 组A
  5. 不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
  6. 重复步骤 1 ~ 4
  7. 限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化

 

复制代码
# 重启系统
reboot

# 挂载 memcg
mount -t cgroup -o memory memcg /mnt/cgroup

# 创建 组A
mkdir /mnt/cgroup/A

# 将当前 shell 加入到组A
echo $$ > /mnt/cgroup/A/tasks

# 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.
free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
             total       used       free     shared    buffers     cached
Mem:          1843        122       1721          0          9         43
-/+ buffers/cache:         68       1774
Swap:         3888          0       3888
             total       used       free     shared    buffers     cached
Mem:          1843       1744         99          0         26       1614
-/+ buffers/cache:        104       1739
Swap:         3888          0       3888

# 重启系统
reboot

# 挂载 memcg
mount -t cgroup -o memory memcg /mnt/cgroup

# 创建 组A
mkdir /mnt/cgroup/A

# 将当前 shell 加入到组A
echo $$ > /mnt/cgroup/A/tasks

# 限制 组A 的内存使用量最大为 10MB
echo 10M > /mnt/cgroup/A/memory.limit_in_bytes

# 测试限制内存为 10MB 时, 内存的使用情况.
rm -rf linux-source-3.2.tar.gz
free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
             total       used       free     shared    buffers     cached
Mem:          1843        122       1721          0         10         43
-/+ buffers/cache:         68       1774
Swap:         3888          0       3888
             total       used       free     shared    buffers     cached
Mem:          1843        194       1649          0         14         48
-/+ buffers/cache:        131       1712
Swap:         3888          0       3888
复制代码

从上面的结果可以看出限制内存是起了作用的.

不限制内存时, tar 压缩前后 buffer + cache 内存从 (9MB + 43MB) ==> (26MB + 1614MB)  增大了 1588MB

限制内存后, tar 压缩前后 buffer + cache 内存从 (10MB + 43MB) ==> (14MB + 48MB)  增大了 9MB

 

总结

简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行.

cgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,

还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值