
我在运维一台部署于香港的数据中心的物理服务器时,多个内部业务共用同一宿主机资源,经常因某个进程瞬时占满CPU或吃掉内存,导致其他关键服务抖动甚至OOM。我决定使用Linux原生的资源控制机制——cgroup v2,从CPU与内存两个维度,对业务服务进行隔离与限流,确保整体系统稳定性。
下面是我在香港裸金属服务器上,基于Ubuntu 22.04内核5.15+的实操路径。
一、前置准备:确认系统支持cgroup v2
首先我需要确认服务器内核版本支持cgroup v2,并且启用了统一层级控制。
uname -r
# 输出应为5.10及以上,例如:5.15.0-91-generic
mount | grep cgroup2
# 输出应包含 cgroup2 on /sys/fs/cgroup
如果系统未启用cgroup v2统一层级,我通过以下方式调整GRUB启动参数:
sudo vim /etc/default/grub
# 修改或追加如下行:
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"
# 更新GRUB并重启:
sudo update-grub
sudo reboot
二、创建统一的业务资源控制目录
在cgroup v2下,所有控制器都挂载在/sys/fs/cgroup统一树状目录中。我为两个业务进程分别创建资源子组:
cd /sys/fs/cgroup
# 创建两个cgroup子组
mkdir -p service-a
mkdir -p service-b
为了系统能应用资源限制,我需要为控制器开启委托(部分发行版如Arch会自动配置,Ubuntu需手动):
# 确保我们有权限配置子组
chown -R root:$(whoami) /sys/fs/cgroup/service-*
chmod 755 /sys/fs/cgroup/service-*
三、配置CPU限流参数
cgroup v2使用cpu.max文件控制CPU限流。格式为:
cpu.max = <quota> <period>
单位是微秒(µs),例如每100ms允许使用20ms的CPU,表示20%限额。
# 限制A业务最多使用1核的50%
echo "50000 100000" > /sys/fs/cgroup/service-a/cpu.max
# B业务限制为单核20%
echo "20000 100000" > /sys/fs/cgroup/service-b/cpu.max
如果某服务可以抢占所有CPU资源,我也可以设置为无限制:
echo "max 100000" > /sys/fs/cgroup/service-b/cpu.max
四、配置内存限制与OOM保护
- cgroup v2的内存控制主要涉及两个文件:
- memory.max: 最大可用内存(强限制)
- memory.high: 超过后将进入soft reclaim状态,系统会优先回收
例如我希望A服务最多用1GB,B服务用512MB:
echo $((1024*1024*1024)) > /sys/fs/cgroup/service-a/memory.max
echo $((512*1024*1024)) > /sys/fs/cgroup/service-b/memory.max
可以加上memory.oom.group=1实现组级别OOM kill:
echo 1 > /sys/fs/cgroup/service-a/memory.oom.group
echo 1 > /sys/fs/cgroup/service-b/memory.oom.group
五、将业务进程挂载到指定cgroup
一旦子组配置完成,需要把服务的PID加入对应的cgroup.procs文件。
假设A服务的主进程PID为12345,B服务为23456:
echo 12345 > /sys/fs/cgroup/service-a/cgroup.procs
echo 23456 > /sys/fs/cgroup/service-b/cgroup.procs
也可以在启动服务时手动绑定:
# 预绑定并启动
echo $$ > /sys/fs/cgroup/service-a/cgroup.procs
exec ./run-service-a
或通过systemd方式(见后续章节)自动管理绑定。
六、进阶:结合systemd自动化cgroup绑定
为了实现更自动化的管理,我将资源限制写入systemd服务文件。例如为service-a创建/etc/systemd/system/service-a.service:
[Unit]
Description=A业务服务
After=network.target
[Service]
ExecStart=/opt/bin/service-a
CPUQuota=50%
MemoryMax=1G
MemoryHigh=768M
Slice=service-a.slice
[Install]
WantedBy=multi-user.target
创建对应slice文件以确保隔离:
# /etc/systemd/system/service-a.slice
[Slice]
CPUAccounting=true
MemoryAccounting=true
加载后启用服务即可:
systemctl daemon-reexec
systemctl daemon-reload
systemctl enable --now service-a
七、实时监控资源使用
cgroup v2支持直接读取当前资源使用情况:
# 查看内存使用
cat /sys/fs/cgroup/service-a/memory.current
# 查看CPU使用累计时间(纳秒)
cat /sys/fs/cgroup/service-a/cpu.stat
配合ps, top, systemd-cgls、systemd-cgtop等工具能实现实时可视化监控。
八、总结与实践效果
完成配置后,我对这台香港物理机上的业务进行了系统级的资源隔离。A服务在高负载时被硬性限在50% CPU与1GB内存以内,避免了过去某个模块因逻辑异常吃满资源拖垮全局的情况。
与传统nice, ulimit, taskset等方法相比,cgroup v2具备:
- 多维度(CPU/内存/IO等)精细化控制
- 统一层级、继承清晰、系统稳定
- 与systemd无缝集成,支持大规模部署
在生产环境中,特别是容器未引入或部分组件依赖系统服务时,cgroup v2提供了比容器更轻量、颗粒度更细的控制能力,是我在香港物理服务器中强烈推荐的隔离手段。











