CGroups 资源控制实战
一、实战目的
能够查看 cgroups 基本信息,了解容器化中,操作系统是真正的资源控制层,对 cpu和内存的控制有一定的理解。
二、基础知识
1.pidstat
pidstat
是一个在 Linux 系统中用于监控和分析单个进程性能的强大命令行工具。它是 sysstat
工具包的一部分,该工具包提供了多种用于系统性能监控的实用程序。pidstat
命令可以生成关于进程活动各个方面的详细统计信息,包括 CPU 使用率、内存消耗、I/O 操作、上下文切换等
主要功能
CPU 使用率:监控进程占用的 CPU 时间百分比,帮助识别高 CPU 占用的进程。
内存使用情况:显示进程的内存使用情况,包括常驻内存集(RSS)、虚拟内存大小(VSZ)以及页面错误等信息。
I/O 活动:跟踪进程的 I/O 操作,例如读写请求的数量和速率,帮助发现 I/O 密集型进程。
上下文切换:统计进程的上下文切换次数,包括自愿和非自愿切换,有助于分析调度问题。
线程统计信息:支持查看多线程应用程序中每个线程的资源使用情况。
任务切换频率:提供任务运行队列长度和任务切换频率的信息,帮助评估系统的调度负载。
语法:
pidstat [ 选项 ] [ <时间间隔> ] [ <次数> ]
一些常用的 pidstat
命令选项及其作用:
-u
:显示 CPU 使用率统计信息,默认参数-r
:显示内存使用情况统计信息。-d
:显示 I/O 统计信息。-w
:显示上下文切换统计信息。-t
:显示线程级别的统计信息。-l
:显示命令名和所有参数-p <PID>
:指定要监控的进程 ID(PID)。如果使用ALL
,则显示所有进程的统计信息。<interval>
:设置统计信息的刷新间隔(单位为秒)。<count>
:设置统计信息的输出次数。
安装
Ubuntu 安装
#卸载
apt remove sysstat -y
#安装
apt install sysstat -yCentOS 安装
#卸载
yum remove sysstat -y
#安装
yum install sysstat -y
示例用法:
1. 查看所有进程的 CPU 使用情况 每隔 2 秒刷新一次,共输出 2 次
07:57:11 PM UID PID %usr %system %guest %wait %CPU CPU Command
07:57:13 PM 0 754 0.00 0.50 0.00 0.00 0.50 1 AliYunDunUpdate
时间戳 | 07:57:13 PM | 统计信息的时间点,格式为 HH:MM:SS AM/PM 。 |
---|---|---|
UID | 0 | 进程的所有者用户 ID。0 表示超级用户(root )。 |
PID | 754 | 进程的唯一标识符(进程 ID)。 |
%usr | 0.00 | 进程在用户空间中消耗的 CPU 时间百分比。0.00% 表示没有显著的用户级计算任务。 |
%system | 0.50 | 进程在内核空间中消耗的 CPU 时间百分比。0.50% 表示有少量内核操作(如系统调用)。 |
%guest | 0.00 | 进程在虚拟化环境中运行客户机操作系统所消耗的 CPU 时间百分比。0.00% 表示无虚拟化任务。 |
%wait | 0.00 | 进程等待 I/O 操作完成的时间百分比。0.00% 表示没有因 I/O 阻塞的情况。 |
%CPU | 0.50 | 进程总的 CPU 使用率。0.50% 是 %usr 和 %system 的总和。 |
CPU | 1 | 运行该进程的 CPU 核心编号。1 表示该进程当前运行在 CPU 核心 1 上。 |
Command | AliYunDunUpdate | 启动该进程的命令名称。AliYunDunUpdate 是阿里云安全服务的一个组件,用于更新安全规则等。 |
2.查看特定进程的内存使用情况–显示 PID 为 994 的进程的内存使用情况
minflt/s | 0.00 | 每秒发生的次要页面错误数(minor page faults)。0.00 表示没有发生内存页错误。 |
---|---|---|
majflt/s | 0.00 | 每秒发生的主要页面错误数(major page faults)。0.00 表示没有发生需要从磁盘加载的页面错误。 |
VSZ | 1792088 | 虚拟内存大小(Virtual Memory Size),单位为 KB。表示进程占用的虚拟内存总量。 |
RSS | 10928 | 常驻内存集(Resident Set Size),单位为 KB。表示进程实际占用的物理内存大小。 |
%MEM | 0.64 | 进程占用的物理内存百分比。0.64% 表示该进程占用了系统总内存的 0.64%。 |
Command | mysqld | 启动该进程的命令名称。mysqld 是 MySQL 数据库服务的主进程。 |
3.查看I/O活动–显示所有进程的 I/O 操作统计信息
4. 查看上下文切换统计信息—显示所有进程的上下文切换信息
5. 查看线程级别的 CPU 使用率—查看所有进程中每个线程CPU使用率
2.stress
stress
是一个用于在 Linux 系统中模拟高负载的工具,常用于测试系统的稳定性和性能极限。它可以人为地施加 CPU、内存、I/O 和磁盘压力,以观察系统在高负载情况下的表现。
stress
的主要功能
CPU 压力测试
- 通过生成繁忙的计算任务(如平方根运算)来占用 CPU 资源。
- 可以指定使用的 CPU 核心数量。
内存压力测试
- 分配大量内存并持续访问,模拟内存使用高峰。
- 可以指定分配的内存大小和分配的数量。
I/O 压力测试
- 通过频繁读写文件来模拟 I/O 密集型操作。
- 可以指定并发的 I/O 操作数量。
磁盘压力测试
- 创建和删除大量临时文件,模拟磁盘密集型操作。
- 可以指定创建的文件数量和文件大小。
安装
Ubuntu
#卸载
apt remove stress -y
#安装
apt install stress -yCentOS
#卸载
yum remove stress -y
#安装
yum install stress -y
常用命令选项
-c, --cpu N:产生 N 个进程,每个进程都循环调用 sqrt 函数产生 CPU 压力。
-i, --io N:产生 N 个进程,每个进程循环调用 sync 将内存缓冲区内容写到磁盘上,产生 IO 压力。通过系统调用 sync 刷新内存缓冲区数据到磁盘中,以确保同步。如果缓冲区内数据较少,写到磁盘中的数据也较少,不会产生 IO 压力。在 SSD 磁盘环境中尤为明显,很可能 iowait 总是 0,却因为大量调用系统调用 sync,导致系统 CPU 使用率 sys 升高。
-m, --vm N:产生 N 个进程,每个进程循环调用 malloc/free 函数分配和释放内存。
–vm-bytes B:指定分配内存的大小
–vm-keep:一直占用内存,区别于不断的释放和重新分配(默认是不断释放并重新分配内存)
-d, --hdd N:产生 N 个不断执行 write 和 unlink 函数的进程(创建文件,写入内容,删除文件)
–hdd-bytes B:指定文件大小
-t, --timeout N:在 N 秒后结束程序
-q, --quiet:程序在运行的过程中不输出信息
示例用法:
1.对 CPU 施加压力–启动 4 个 CPU 工作线程,持续 30 秒。
2.对 I/O 施加压力–启动 4 个 I/O 工作线程,持续 20 秒。
3.对内存施加压力
4.对磁盘施加压力
三、实操一-cgroups信息查看
在 Linux 系统中,cgroups(Control Groups)用于限制、控制和隔离进程组的资源使用。cgroups 有两个主要版本:cgroups v1 和 cgroups v2
1. 查看 cgroups 版本
方法 1:通过 /proc/filesystems
- 如果输出中包含
cgroup
和cgroup2
,说明系统同时支持 cgroups v1 和 vgroups v2。 - 如果仅包含
cgroup2
,说明系统仅支持 cgroups v2。 - 如果仅包含
cgroup
,说明系统仅支持 cgroups v1。
方法 2:通过 /sys/fs/cgroup
- 如果目录下只有一个
cgroup.procs
文件和一些通用文件(如cpu.max
,memory.max
),说明系统使用的是 cgroups v2。 - 如果目录下有多个子目录(如
cpu
,memory
,blkio
等),说明系统使用的是 cgroups v1。
2. 查看 cgroups 子系统
方法 1:通过 /proc/cgroups
subsys_name
: 子系统名称(如cpu
,memory
等)。enabled
: 是否启用(1
表示启用,0
表示禁用)。
方法 2:通过 lssubsys
安装 cgroup-tools
包后,可以使用以下命令查看子系统及其挂载点:
3. 查看 cgroups 挂载信息
方法 1:通过 mount
命令
方法 2:通过 /proc/mounts
4. 查看一个进程上的 cgroup 限制
每个进程都属于一个或多个 cgroups,其信息存储在 /proc/<PID>/cgroup
文件中。以下是具体操作步骤:
步骤 1:查看进程所属的 cgroup
cat /proc/<PID>/cgroup
字段解释
0
- 表示 cgroup 的层级编号。
- 在 cgroups v2 中,只有一个统一的层级(编号为
0
),所有的子系统(如 CPU、内存、I/O 等)都挂载在这个层级上。
::
- 分隔符,用于分隔层级编号和 cgroup 路径。
- 在 cgroups v2 中,子系统名称不再显示,因为所有子系统都共享同一个层级。
/system.slice/mysql.service
- 表示该进程所属的 cgroup 路径。
/system.slice/
是 systemd 管理的服务的标准路径,表示这是一个系统服务。mysql.service
是具体的服务名称,说明该进程是由mysql.service
启动的。
进一步查看 mysql.service
的资源限制。以下是具体操作步骤:
1.查看 CPU 限制
wuxu@Nanyiroot:~$ cat /sys/fs/cgroup/system.slice/mysql.service/cpu.max
max 100000
- 第一个值(
max
或具体数字)表示 CPU 时间配额。 - 第二个值(
100000
)表示 CPU 时间周期(单位为微秒)。 - 如果第一个值是
max
,表示没有限制。
2. 查看内存限制
wuxu@Nanyiroot:~$ cat /sys/fs/cgroup/system.slice/mysql.service/memory.max
max
- 如果输出为2147483648,表示内存限制为 2 GB(单位为字节)。
- 如果值为
max
,表示没有限制。
- 查看当前内存使用量
wuxu@Nanyiroot:~$ cat /sys/fs/cgroup/system.slice/mysql.service/memory.current
52428800
表示当前内存使用量为 50 MB(单位为字节)
- 查看磁盘 I/O 限制
cat /sys/fs/cgroup/system.slice/mysql.service/io.max
8:0 rbps=1048576 wbps=524288 riops=max wiops=max
8:0
表示设备号(主设备号:次设备号)。rbps
和wbps
分别表示每秒读取和写入的最大字节数。riops
和wiops
分别表示每秒读取和写入的最大 I/O 操作数。
总结
通过 cat /proc/994/cgroup
,我们确认了进程 994
(mysqld
)属于 cgroups v2,并且其资源管理由 /system.slice/mysql.service
控制。接下来,您可以根据需要查看具体的资源限制和使用情况,例如 CPU、内存、I/O 等。
如果您想进一步优化 MySQL 的性能,可以根据这些资源限制调整配置文件(如 my.cnf
),或者通过 systemd 修改 mysql.service
的 cgroup 参数。
四、实操二(使用 cgroupsv2 对内存进行控制)
系统使用的是 cgroups v2,我们可以通过直接操作 /sys/fs/cgroup
文件系统来创建和管理 cgroups,并对内存进行控制。以下是详细的实操步骤:
目标
通过 cgroups v2 限制一个进程的内存使用量。例如,限制某个进程最多只能使用 100 MB 内存。
步骤
1. 创建一个新的 cgroup
在 cgroups v2 中,所有子系统的资源控制都集中在一个统一的挂载点下(通常是 /sys/fs/cgroup
)。我们可以通过创建一个新的目录来定义一个新的 cgroup。
sudo mkdir /sys/fs/cgroup/my_memory_limit
my_memory_limit
是我们为这个 cgroup 定义的名称,您可以根据需要更改。
2. 设置内存限制
进入新创建的 cgroup 目录,并设置内存限制。
echo 100M | sudo tee /sys/fs/cgroup/my_memory_limit/memory.max
memory.max
文件用于设置内存限制。100M
表示限制为 100 MB。您也可以使用其他单位,如50M
(50 MB)、1G
(1 GB)等。- 如果希望取消限制,可以将值设置为
max
:echo max | sudo tee /sys/fs/cgroup/my_memory_limit/memory.max
3. 启动一个受控进程
将一个进程加入到这个 cgroup 中,以使其受到内存限制。
方法 1:手动启动进程并添加到 cgroup
启动一个测试进程(例如 stress
工具):
stress --vm 1 --vm-bytes 200M --timeout 60s &
--vm 1
:启动 1 个内存工作线程。--vm-bytes 200M
:每个线程尝试分配 200 MB 内存。--timeout 60s
:运行 60 秒后自动退出。
获取该进程的 PID:
pidof stress
将该进程的 PID 添加到 cgroup 的 cgroup.procs
文件中:
echo <PID> | sudo tee /sys/fs/cgroup/my_memory_limit/cgroup.procs
<PID>
是上一步获取的进程 ID。
方法 2:直接在 cgroup 中启动进程
您也可以直接在 cgroup 中启动进程,而不需要手动添加 PID:
sudo systemd-run --scope -p MemoryMax=100M stress --vm 1 --vm-bytes 200M --timeout 60s
--scope
:创建一个新的 cgroup 范围。-p MemoryMax=100M
:设置内存限制为 100 MB。
4. 验证内存限制
观察进程是否受到内存限制的影响。
方法 1:查看 cgroup 的内存使用情况
cat /sys/fs/cgroup/my_memory_limit/memory.current
- 输出的是当前内存使用量(单位为字节)。
- 如果进程尝试分配超过 100 MB 的内存,它会被限制或被内核终止(OOM Killer)。
方法 2:检查系统日志
如果内存超出限制,内核可能会触发 OOM(Out of Memory)机制,终止进程。您可以通过以下命令查看系统日志:
dmesg | grep -i oom
5. 清理 cgroup
完成测试后,可以删除 cgroup 以释放资源。
sudo rmdir /sys/fs/cgroup/my_memory_limit
完整示例
以下是一个完整的示例流程:
# 1. 创建新的 cgroup
sudo mkdir /sys/fs/cgroup/my_memory_limit# 2. 设置内存限制为 100 MB
echo 100M | sudo tee /sys/fs/cgroup/my_memory_limit/memory.max# 3. 启动一个测试进程(尝试分配 200 MB 内存)
stress --vm 1 --vm-bytes 200M --timeout 60s &# 4. 获取进程 PID 并添加到 cgroup
pidof stress | sudo tee /sys/fs/cgroup/my_memory_limit/cgroup.procs# 5. 验证内存使用情况
cat /sys/fs/cgroup/my_memory_limit/memory.current# 6. 检查系统日志(可选)
dmesg | grep -i oom# 7. 清理 cgroup
sudo rmdir /sys/fs/cgroup/my_memory_limit
注意事项
OOM Killer
- 如果进程尝试分配的内存超过限制,内核可能会触发 OOM Killer 终止进程。
- 您可以通过以下命令禁用 OOM Killer(仅适用于测试环境):
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
权限问题
- 操作
/sys/fs/cgroup
文件系统通常需要超级用户权限(sudo
)。
工具安装
- 如果需要使用
stress
工具,请确保已安装:sudo apt-get install stress # Ubuntu/Debian sudo yum install stress # CentOS/RHEL
总结
通过上述步骤,您可以使用 cgroups v2 对进程的内存使用进行限制。这种方法简单直观,适用于现代 Linux 系统。如果您有更多需求(如限制 CPU、I/O 等),可以参考类似的文件和目录结构进行配置。
五、实操三、使用 cgroups2 对 cpu 进行控制
在 Linux 系统中,cgroups v2 提供了对 CPU 资源的细粒度控制。通过 cgroups v2,您可以限制进程组的 CPU 使用时间、优先级等资源。以下是一个实操示例,展示如何使用 cgroups v2 对 CPU 进行控制。
目标
通过 cgroups v2 限制一个进程的 CPU 使用量。例如,限制某个进程最多只能使用 50% 的一个 CPU 核心。
步骤
1. 创建一个新的 cgroup
在 cgroups v2 中,所有子系统的资源控制都集中在一个统一的挂载点下(通常是 /sys/fs/cgroup
)。我们可以通过创建一个新的目录来定义一个新的 cgroup。
sudo mkdir /sys/fs/cgroup/my_cpu_limit
my_cpu_limit
是我们为这个 cgroup 定义的名称,您可以根据需要更改。
2. 设置 CPU 限制
进入新创建的 cgroup 目录,并设置 CPU 使用限制。
方法 1:限制 CPU 时间配额
CPU 限制通过 cpu.max
文件进行配置。格式为:
<quota> <period>
<quota>
: 表示允许的最大 CPU 时间(单位为微秒)。<period>
: 表示 CPU 时间周期(单位为微秒)。
例如,限制进程最多使用 50% 的一个 CPU 核心:
echo "50000 100000" | sudo tee /sys/fs/cgroup/my_cpu_limit/cpu.max
50000
: 在每个周期内,允许使用的最大 CPU 时间为 50,000 微秒(即 50 毫秒)。100000
: 每个周期的时间长度为 100,000 微秒(即 100 毫秒)。- 结果是,进程最多只能使用 50% 的一个 CPU 核心。
方法 2:取消限制
如果希望取消 CPU 限制,可以将值设置为 max
:
echo "max 100000" | sudo tee /sys/fs/cgroup/my_cpu_limit/cpu.max
3. 启动一个受控进程
将一个进程加入到这个 cgroup 中,以使其受到 CPU 限制。
方法 1:手动启动进程并添加到 cgroup
启动一个测试进程(例如 stress
工具):
stress --cpu 2 --timeout 60s &
--cpu 2
: 启动 2 个 CPU 工作线程。--timeout 60s
: 运行 60 秒后自动退出。
获取该进程的 PID:
pidof stress
将该进程的 PID 添加到 cgroup 的 cgroup.procs
文件中:
echo <PID> | sudo tee /sys/fs/cgroup/my_cpu_limit/cgroup.procs
<PID>
是上一步获取的进程 ID。
方法 2:直接在 cgroup 中启动进程
您也可以直接在 cgroup 中启动进程,而不需要手动添加 PID:
sudo systemd-run --scope -p CPUQuota=50% stress --cpu 2 --timeout 60s
--scope
: 创建一个新的 cgroup 范围。-p CPUQuota=50%
: 设置 CPU 使用限制为 50%。
4. 验证 CPU 限制
观察进程是否受到 CPU 限制的影响。
方法 1:查看 CPU 使用情况
运行 top
或 htop
命令,查看 stress
进程的 CPU 使用率:
top
- 如果限制生效,您会看到
stress
进程的 CPU 使用率接近 50%(假设系统只有一个 CPU 核心)。
方法 2:查看 cgroup 的 CPU 统计信息
cat /sys/fs/cgroup/my_cpu_limit/cpu.stat
- 输出示例:
usage_usec 123456789 user_usec 67890123 system_usec 56789012 nr_periods 1234 nr_throttled 12 throttled_usec 123456
nr_periods
: 调度周期的数量。nr_throttled
: 被限制的周期数量。throttled_usec
: 被限制的总时间(单位为微秒)。
5. 清理 cgroup
完成测试后,可以删除 cgroup 以释放资源。
sudo rmdir /sys/fs/cgroup/my_cpu_limit
完整示例
以下是一个完整的示例流程:
# 1. 创建新的 cgroup
sudo mkdir /sys/fs/cgroup/my_cpu_limit# 2. 设置 CPU 限制为 50%
echo "50000 100000" | sudo tee /sys/fs/cgroup/my_cpu_limit/cpu.max# 3. 启动一个测试进程(尝试占用 2 个 CPU 核心)
stress --cpu 2 --timeout 60s &# 4. 获取进程 PID 并添加到 cgroup
pidof stress | sudo tee /sys/fs/cgroup/my_cpu_limit/cgroup.procs# 5. 验证 CPU 使用情况
top# 6. 查看 cgroup 的 CPU 统计信息
cat /sys/fs/cgroup/my_cpu_limit/cpu.stat# 7. 清理 cgroup
sudo rmdir /sys/fs/cgroup/my_cpu_limit
总结
通过上述步骤,您可以使用 cgroups v2 对进程的 CPU 使用进行限制。这种方法简单直观,适用于现代 Linux 系统。如果您有更多需求(如限制内存、I/O 等),可以参考类似的文件和目录结构进行配置。