Cgroup使用进阶

本文深入探讨了Cgroup的资源限制设置,包括使用cgset调整子系统参数,使用cgclassify移动进程到控制组,以及利用cgred服务实现进程重启后的自动限制。此外,还介绍了如何在进程启动时通过cgexec将其置于控制组,并提供了获取控制组信息的各种方法。

About

在我的前面两篇文章中,分别介绍了cgroup的一些基本概念,和如何去管理层次结构和control group还有如何附加子系统。但是到目前为止仍旧没有触及cgroup中最核心的东西也就是资源限制。前面的文章中仅仅说的是如何把子系统附加到某个层次上。至于如何设置子系统来限制资源,如何针对某些进程来限制都还没有涉及。那么本篇博文谈的就是这两点。

Setting Parameters

当我们将一个子系统附加到一个层次中,我们必须去调节对应子系统的参数才能够达到资源限制的目的。给某个子系统设置参数需要用到cgset命令,但是需要注意一个问题就是,使用cgset的权限。不是哪个用户都可以使用cgset对某一个control group下的子系统设置参数。在使用cgcreate命
令创建control group的时候有一个-t和-a选项,这两个可以指定用户可以修改control group中的子系统参数。具体细节可以参考我的上篇博文

先来看下cgset的语法

cgset -r parameter=value path_to_cgroup
path_to_cgroup 是一个相对于root cgroup的一个路径
例如: /cgroup/cpu_and_mem 这个cgroup,并且已经挂载,要想调节这个
cgroup的参数,那么path_to_cgroup就是/ 也可以省略,表示就是cpu_and_mem这个root cgroup自身。
如果是要设置参数的control group是 /cgroup/cpu_and_mem/subgroup
那么path_to_group就是/subgroup

下面是使用cgset设置参数的一个例子:

此时系统上已经挂载了一个/cgroup/cpu_and_mem的root group了
下面这是用来调节subgroup这个control group的最大内存使用量
cgset -r memory.limit_in_bytes=10240000 /subgroup

我们也可以拷贝一个control group的参数到另外一个control group中,操作方式如下:

将subgroup中的子系统参数,拷贝到subgroup2中。
cgset --copy-from /subgroup /subgroup2 

关于每个子系统中的参数的含义我将会在下篇博文中根据实际例子来解释其作用。

Displaying Parameters of Control Groups

cgget命令可以用来查看某个control group中的子系统的参数,也可以使用cat通过文件的方式来查看。cgget显示参数的用法如下:

syntax:
cgget -r parameter list_of_cgroups

example:
cgget -r cpuset.cpus -r memory.limit_in_bytes /subgroup /subgroup2
结果如下
/subgroup:
cpuset.cpus: 
memory.limit_in_bytes: 1024000

/subgroup2:
cpuset.cpus: 
memory.limit_in_bytes: 9223372036854775807

Moving a Process to a Control Group

调节完子系统的参数后基本上就可以达到资源限制的作用了,但是对谁做限制呢?如果我们调节的是root group中的子系统参数,那么将会对整个系统的所有进程做资源限制。这或许不是我们想要的效果,你可以看下每个control group目录下都有一个tasks文件,这个文件中放的是要限制的进程pid,如果是root group那么这个文件中放的是系统上所有进程的pid,如果
是一个刚创建的control group则这个文件是空的。原理搞清楚了,实现起来就简单了,只要将要限制的进程pid,添加到这个文件中就可以实现对这个进程的资源限制了,cgroup同时也提供了一个命令来帮助我们完成这个操作,这个命令叫做cgclassify。语法如下

cgclassify -g subsystems:path_to_cgroup pidlist

下面是一个使用cgclassify来添加进程到指定contrl group中下面是把1251进程添加到subgroup这个control group中
cgclassify -g cpuset:/subgroup 1251
也可以
echo 1251 > /cgroup/cpu_and_mem/subgroup

The cgred Service

考虑一个场景,如果我要对一个vsftpd进程做限制,那么如果使用上面提到的方法来对vsftpd进程做限制,那么存在一个问题就是,每次系统重启都需要重新设置,因为进程的PID发生了变化。好在红帽给我们提供了一个cgred的服务,是随着libcgroup的安装而安装的。通过cgred可以自动帮我们去设置。我们只需要在配置文件中书写规则即可。

配置文件为/etc/cgrules.conf,其文件格式有以下两种:
两种syntax
user subsystems control_group
user:command subsystems control_group
下面是一些设置案例:

maria devices /usergroup
表示任何属于maria这个用户的进程,访问设备子系统的时候都受/usergroup
这个cgroup关于devices子系统的影响。
maria:ftp devices /usergroup/staff/ftp
表示当maria用户使用ftp命令产生的进程会自动移动到包含device子系统的/usergroup/staff/ftp control group中。

关于cgred的配置文件语法还有更多的话题可以谈,再次就介绍到这里为止了。

Starting a Process in a Control Group

上面的谈到的是如何把一个进程移动到某个control group的子系统下,那么如何在进程启动的时候就将其添加到control group中的呢,cgroup提供了一个cgexec命令用来达到这个目的,先来看下这个命令的语法规则:

cgexec -g subsystems:path_to_cgroup command arguments
下面是一个例子,在subgroup这个control group中,执行wget命令:
cgexec -g memory:/subgroup wget http://www.redhat.com

当然除了使用cgexec外,还可以有另外一个方法来在某个control group中执行指定进程。

把当前进程添加到control group中,那么很自然其子进程也是属于这个control group中的
[root@localhost cpu_and_mem]# echo $$ > /cgroup/cpu_and_mem/subgroup/tasks
[root@localhost cpu_and_mem]# wget http://www.redhat.com
但是这种方法存在一个问题就是当wget退出后,当前进程仍然还是属于cgroup中.下面是一种更好的办法:
sh -c "echo \$$ > /cgroup/cpu_and_mem/subgroup/tasks && wget http://www.redhat.com"

Obtaining Information About Control Groups

Finding a Process

寻找一个进程是属于哪个cgroup的,可以运行下面的命令
ps -O cgroup或者是你想指定指定PID进程是属于哪个cgroup的可以运行下面的命令cat /proc/PID/cgroup

Finding a Subsystem

寻找某个子系统的挂载点(也就是所在层次)可以运行下面的命令:
lssubsys -m subsystems

Finding Hierarchies

寻找当前系统上存在的层次可以运行下面的命令:
tree /cgroup

Finding Control Groups

寻找当前系统上存在的control groups(包括root group),可以运行下面的命令:

[root@localhost ~]# lscgroup 
cpuset,memory:/
### Linux 系统进程管理高级使用教程和技巧 #### 1. 使用 `systemd` 和 `systemctl` 进行服务管理和监控 现代 Linux 发行版广泛采用了 `systemd` 初始化系统来替代传统的 SysVinit。这不仅提高了系统的启动效率,还提供了更强大的进程和服务管理功能。 通过 `systemctl` 命令可以方便地查看当前活动的服务状态: ```bash systemctl list-units --type=service --state=running ``` 对于特定服务的操作也非常直观,比如重启 Nginx 服务器可以通过如下命令完成: ```bash sudo systemctl restart nginx.service ``` 还可以设置某个服务随系统自动启动或禁用此行为: ```bash sudo systemctl enable sshd.service # 开启自启 sudo systemctl disable sshd.service # 关闭自启 ``` 这些操作简化了日常维护工作并增强了灵活性[^2]。 #### 2. 利用 cgroups 实现资源限制与隔离 cgroup (control group) 是内核提供的一种机制,用于限制、记录和隔离一组进程所使用的物理资源(CPU, 内存, I/O)。这对于多租户环境下的容器化应用尤为重要。 创建一个新的 cgroup 并为其设定 CPU 权重为例: ```bash cgcreate -g cpu:/myapp echo "800" | sudo tee /sys/fs/cgroup/cpu/myapp/cpu.shares ``` 上述指令会为名为 myapp 的应用程序组分配较高的 CPU 访问优先级[^1]。 #### 3. 掌握调试工具如 `strace`, `lsof` 及其应用场景 当遇到程序异常时,`strace` 工具可以帮助追踪目标程序执行期间产生的所有系统调用及其参数返回值;而 `lsof` 则可用于查询哪些文件被哪个进程打开着,在排查日志读取失败等问题上特别有用。 例如要跟踪 Apache HTTP Server 启动过程中的系统调用可这样做: ```bash strace -o apache_start_trace.log -ff -ttt -s 4096 -p $(pgrep httpd) ``` 这里 `-o` 参数指定了输出文件名,其他选项则分别表示分叉跟踪(`-ff`)、时间戳(`-ttt`)以及最大字符串长度(`-s`). 而对于想要知道 MySQL 数据库正在访问哪些表文件,则可以用: ```bash lsof -u mysql | grep '.ibd$' ``` 这条命令列出了属于用户 'mysql' 下所有的 .ibd 文件(即 InnoDB 表数据)[^4]. #### 4. 自定义信号处理逻辑提升健壮性 Linux 支持多种类型的信号(signal), 它们用来通知进程发生了某些事件。合理利用信号可以让应用程序更好地应对意外情况。例如 SIGTERM 请求优雅终止,SIGUSR1/SIGUSR2 用户自定义用途等. 编写 Python 应用监听 SIGINT(Ctrl+C): ```python import signal import sys def handle_sigint(signum, frame): print('Received SIGINT, cleaning up...') cleanup_resources() sys.exit(0) signal.signal(signal.SIGINT, handle_sigint) print("Press Ctrl+C to exit.") while True: pass ``` 这段脚本注册了一个处理器函数 `handle_sigint()` ,它会在接收到中断请求时触发清理动作后再退出循环[^5].
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值