要限制进程的内存和cpu使用,需通过cgroups v1操作/sys/fs/cgroup文件系统,1. 确认cgroup已挂载,若未挂载则使用mount命令挂载cpu和memory控制器;2. 在/sys/fs/cgroup/cpu和memory下创建名为my_limited_app的目录;3. 设置内存限制为200m,通过echo 200m > memory.limit_in_bytes并设置swappiness为0;4. 设置cpu限制为25%,通过设置cpu.cfs_period_us为100000和cpu.cfs_quota_us为25000;5. 将目标进程pid写入cpu和memory对应cgroup的tasks文件以加入限制;6. 对于新进程,使用cgexec -g cpu,memory:my_limited_app启动命令使其直接在限定环境中运行,整个过程实现了对进程资源使用的有效隔离与控制。

cgroups(control groups)是Linux内核提供的一项强大功能,它允许你对进程组的资源使用进行精细化控制,包括内存和CPU。简单来说,它就像是给服务器上的不同应用划定“地盘”,确保它们不会互相干扰,某个进程失控时也不会拖垮整个系统。
解决方案
要限制进程的内存和CPU使用,我们主要通过操作
/sys/fs/cgroup这个虚拟文件系统来完成。这里以 cgroups v1 版本为例,因为它在很多现有系统上仍然是默认且易于手动操作的。
核心步骤:
-
确定 cgroup 文件系统是否已挂载。 通常情况下,现代Linux发行版都会自动挂载。你可以通过
mount -t cgroup
命令来查看。如果没有,你需要手动挂载,例如:sudo mount -t cgroup -o cpu,memory cgroup /sys/fs/cgroup/cpu_memory
(这里的cpu,memory
是指定要挂载的控制器)。 - 创建新的 cgroup 目录。 这将为你的受限进程创建一个独立的资源组。
- 设置资源限制。 进入新创建的 cgroup 目录,修改相应的控制文件来设定内存和CPU的上限。
-
将进程加入 cgroup。 将目标进程的PID写入到 cgroup 目录下的
tasks
文件中。 -
启动新进程时直接指定 cgroup。 对于新启动的进程,可以使用
cgexec
命令让它直接在指定的 cgroup 中运行。
理解cgroups的工作原理:为什么我们需要它?
我个人觉得,cgroups的出现,就像是给Linux系统装上了一套精密的交通管制系统。想象一下,你的服务器上可能同时跑着Web服务、数据库、后台任务,甚至是一些临时的脚本。如果其中任何一个进程突然“暴走”,比如内存泄漏导致占用大量RAM,或者一个无限循环的计算任务把所有CPU核心都吃光,那整个系统就会变得异常缓慢,甚至直接崩溃。这种经历,相信很多运维或开发者都深有体会,调试起来简直是噩梦。
cgroups就是为了解决这种问题而生的。它通过在内核层面实现资源隔离和管理,将进程组织成一个或多个层次结构(有点像目录树),每个节点(cgroup)都可以拥有自己的资源限制。例如,你可以为一个Web服务器进程组分配50%的CPU和2GB的内存,而为后台分析任务分配20%的CPU和4GB内存。这样,即使后台任务计算量再大,它也无法超过预设的CPU上限,更不会因为内存不足而导致整个系统OOM(Out Of Memory)。它不仅能防止资源滥用,还能确保关键服务的SLA(服务等级协议),这在多租户环境或者资源竞争激烈的场景下尤其重要。
实际操作:如何为特定进程设置CPU和内存限制?
让我们来实际操作一下,给一个假想的“资源消耗大户”进程设置限制。
假设我们要创建一个名为
my_limited_app的cgroup,并将其内存限制在200MB,CPU使用限制在25%。
步骤详解:
免费 盛世企业网站管理系统(SnSee)系统完全免费使用,无任何功能模块使用限制,在使用过程中如遇到相关问题可以去官方论坛参与讨论。开源 系统Web代码完全开源,在您使用过程中可以根据自已实际情况加以调整或修改,完全可以满足您的需求。强大且灵活 独创的多语言功能,可以直接在后台自由设定语言版本,其语言版本不限数量,可根据自已需要进行任意设置;系统各模块可在后台自由设置及开启;强大且适用的后台管理支
-
进入 cgroup 虚拟文件系统: 通常,cgroup控制器会挂载在
/sys/fs/cgroup
下。你可以列出其中的目录,比如cpu
和memory
,它们分别对应CPU和内存的控制器。ls /sys/fs/cgroup/ # 你可能会看到 cpu cpuacct memory blkio devices freezer net_cls net_prio perf_event pids systemd
-
创建 cgroup 目录: 我们将在
cpu
和memory
控制器下分别创建我们的组。sudo mkdir /sys/fs/cgroup/memory/my_limited_app sudo mkdir /sys/fs/cgroup/cpu/my_limited_app
-
设置内存限制: 进入
memory/my_limited_app
目录,修改memory.limit_in_bytes
文件。单位可以是字节,也可以用K、M、G表示。sudo sh -c "echo 200M > /sys/fs/cgroup/memory/my_limited_app/memory.limit_in_bytes" # 还可以设置 swappiness,0 表示尽量不使用 swap,100 表示积极使用 sudo sh -c "echo 0 > /sys/fs/cgroup/memory/my_limited_app/memory.swappiness"
-
设置CPU限制: 进入
cpu/my_limited_app
目录。CPU限制通过cpu.cfs_period_us
和cpu.cfs_quota_us
来控制。cfs_period_us
是一个时间周期(微秒),cfs_quota_us
是在这个周期内允许使用的CPU时间(微秒)。 例如,要限制为25%的CPU,我们可以设置周期为100ms (100000us),配额为25ms (25000us)。sudo sh -c "echo 100000 > /sys/fs/cgroup/cpu/my_limited_app/cpu.cfs_period_us" sudo sh -c "echo 25000 > /sys/fs/cgroup/cpu/my_limited_app/cpu.cfs_quota_us" # 还可以使用 cpu.shares,这是一个相对权重,默认是1024。 # 如果有两个组,一个 shares 是 1024,另一个是 512,那么在CPU资源紧张时,前者会获得两倍于后者的CPU时间。 # sudo sh -c "echo 256 > /sys/fs/cgroup/cpu/my_limited_app/cpu.shares"
-
将现有进程加入 cgroup: 假设你的进程PID是
12345
。sudo sh -c "echo 12345 > /sys/fs/cgroup/memory/my_limited_app/tasks" sudo sh -c "echo 12345 > /sys/fs/cgroup/cpu/my_limited_app/tasks"
-
启动新进程时直接指定 cgroup: 如果你要启动一个新进程并让它直接在
my_limited_app
cgroup 中运行,可以使用cgexec
命令(需要安装cgroup-tools
或libcgroup-tools
包)。sudo cgexec -g cpu,memory:my_limited_app your_command_here # 例如: # sudo cgexec -g cpu,memory:my_limited_app stress -c 4 -m 1 --vm-bytes 300M # (注意:这里的 stress 命令如果超过内存限制,可能会被 OOM kill)
常见问题与进阶考量:cgroups v1 vs v2及监控技巧
cgroups的世界其实比表面看起来要复杂一些,尤其是当涉及到v1和v2两个主要版本时。
cgroups v1 vs v2:
目前我们操作的例子是基于 cgroups v1,它是Linux上广泛使用的版本,特点是每个控制器(如
cpu、
memory)都有自己的独立层级结构。这意味着你可能需要为同一个进程在不同的控制器下创建并管理独立的cgroup路径。它的优点是灵活,可以针对特定资源进行细粒度控制。
而 cgroups v2 是更新、更统一的版本,它提供了一个单一的、统一的层级结构。所有控制器都挂载在同一个根目录下,并且子cgroup会继承父cgroup的所有控制器。v2的设计更加简洁和一致,解决了v1中一些层级结构和资源分配的复杂性问题。现代的发行版,尤其是使用
systemd的系统,越来越多地转向v2。不过,对于手动操作和理解基础概念,v1的例子依然非常直观和有用。在实际生产环境中,你更多会通过
systemd的
Delegate=yes或
CPUQuota、
MemoryLimit等参数来间接使用cgroups的功能,而非直接操作文件。
监控技巧:
光设置限制还不够,你还需要知道你的cgroup是否真的在工作,以及进程的资源使用情况。
-
检查当前限制: 你可以直接
cat
对应cgroup目录下的控制文件来查看当前设置的限制值。cat /sys/fs/cgroup/memory/my_limited_app/memory.limit_in_bytes cat /sys/fs/cgroup/cpu/my_limited_app/cpu.cfs_quota_us
-
查看资源使用情况: 每个cgroup目录下都有
memory.usage_in_bytes
和cpuacct.usage
等文件,它们会告诉你该cgroup中所有进程的总资源消耗。cat /sys/fs/cgroup/memory/my_limited_app/memory.usage_in_bytes cat /sys/fs/cgroup/cpu/my_limited_app/cpuacct.usage # memory.stat 提供更详细的内存统计信息,比如缓存、活跃内存等 cat /sys/fs/cgroup/memory/my_limited_app/memory.stat
调试与陷阱: 有时候,你会发现一个进程明明被限制了,但行为还是不尽如人意,这时候就需要深入日志和统计文件了。我记得有一次,我给一个Java应用设置了内存限制,结果它还是时不时被OOM杀死,后来才发现是JVM自己的内存管理机制和cgroup的限制在打架,需要额外调整JVM参数(比如
-Xmx
要小于cgroup的限制)。这种细节,真的得自己踩过坑才能体会。另一个常见问题是,进程启动后没有正确进入cgroup,或者进程又派生了子进程,而子进程没有继承cgroup限制。务必确认tasks
文件中包含了所有你希望限制的PID。
cgroups是一个非常底层且强大的工具,理解并善用它,能让你在管理Linux系统资源时更加游刃有余。









