Linux系统资源动态调度容器防止资源抢占

多容器部署在同一台云服务器上,资源互相抢占往往导致关键业务响应变慢甚至卡死。
解决思路不是停掉容器,而是给每个容器设定资源上限和权重,再根据负载动态调整调度参数。
本文以 Docker 和 systemd 环境为例,介绍一套零基础可执行的动态调度配置方案,涉及 cgroup v2、CPU 权重、内存锁定和动态调整命令,完成后可显著改善资源抢占问题。

先确定你的环境是否支持动态调度

动态调度依赖两项底层能力:一是内核 cgroup 版本,Docker 20.10 以上默认开启 cgroup v2,可通过 cat /sys/fs/cgroup/cgroup.controllers 查看,如果输出中有 cpumemory,说明支持;
二是 systemd 版本在 245 以上,可通过 systemd --version 确认。

检查完这两项后,建议先把 Docker 的 cgroup 驱动切换为 systemd,否则 systemd 和 Docker 各自管理 cgroup 会互相覆盖配置。
操作方式是在 /etc/docker/daemon.json 中写入以下内容:

{
    "exec-opts": ["native.cgroupdriver=systemd"]
}

保存后执行 systemctl restart docker

给容器设置资源配额并动态调整

第一步,设置初始限制。 创建容器时,用 --cpus 限定容器最多使用的 CPU 核数,用 --memory 限定内存上限,用 --memory-swap 限定 swap 总量,避免容器无限占用宿主机内存。
例如:

docker run -d --name my-app \
  --cpus="1.5" \
  --memory="1g" \
  --memory-swap="1g" \
  --cpu-shares=2048 \
  nginx:latest

--cpu-shares 是相对权重,默认值是 1024,设为 2048 表示该容器在 CPU 繁忙时获得两倍于默认容器的调度机会。

第二步,动态调整运行中的容器。 当业务高峰来临时,希望临时增加某个容器的 CPU 核数,不需要重启容器,直接执行:

docker update --cpus="2.0" --cpu-shares=3072 my-app

如果发现某容器内存占用异常,也可以直接收紧:

docker update --memory="512m" --memory-swap="512m" my-app

需要注意,内存限制只能调小后才能调大,实际变更以容器重启后的最终配置为准。

第三步,使用 systemd 对容器服务做动态调度。 如果你的容器是通过 systemd 管理,可以编辑服务单元文件,在 [Service] 段加入 CPUWeight 项:

[Service]
CPUWeight=50
MemoryMax=1G

CPUWeight 是 cgroup v2 的权重参数,取值范围为 1-10000,默认 100,数值越高,获得 CPU 时间片越多。
修改后执行 systemctl daemon-reload && systemctl restart 容器服务名 即可生效。

自动检测负载并动态调整调度参数

手动调整适合低频运维,若要实现真正的动态调度,用脚本定期检查 CPU 占用并自动调整更实用。
以下脚本每 60 秒读取容器 CPU 使用率,超过 80% 就提高其 CPU 份额,低于 20% 就降低:

#!/bin/bash
CONTAINER="my-app"
MAX_SHARES=4096
MIN_SHARES=512

while true; do
    USAGE=$(docker stats --no-stream --format "{{.CPUPerc}}" $CONTAINER | sed 's/%//' | cut -d. -f1)
    CURRENT=$(docker inspect --format '{{.HostConfig.CpuShares}}' $CONTAINER)
    if [ -n "$USAGE" ] && [ "$USAGE" -gt 80 ]; then
        NEW=$((CURRENT * 2))
        if [ $NEW -le $MAX_SHARES ]; then
            docker update --cpu-shares=$NEW $CONTAINER
            echo "$(date): 负载过高,cpu-shares 调整至 $NEW"
        fi
    elif [ -n "$USAGE" ] && [ "$USAGE" -lt 20 ]; then
        NEW=$((CURRENT / 2))
        if [ $NEW -ge $MIN_SHARES ]; then
            docker update --cpu-shares=$NEW $CONTAINER
            echo "$(date): 负载较低,cpu-shares 调整至 $NEW"
        fi
    fi
    sleep 60
done

注意,这个脚本只对长期运行的生产容器适用,且不建议在数据库容器上自动调低权重,避免数据库响应质量下降。

避坑说明:这四个问题最容易误导人

第一,--cpus--cpu-shares 不是同一层面的限制。 --cpus 是硬限制,超出后容器被 throttle;--cpu-shares 只是相对权重,只在多容器争抢时发挥作用。
只设置 --cpu-shares 而不设置 --cpus,无法防止 CPU 密集型容器独占整机。

第二,
内存限制不要随意搭配 swap。
--memory-swap 必须大于等于 --memory
如果设置为相等数值,
相当于容器无法使用 swap,
能有效避免容器 swap 写入拖垮磁盘 IO,
但对内存需求突增的容器容易触发 OOM。

第三,cgroup v1 和 v2 的权重参数不通用。 在 cgroup v1 中,Docker 的 --cpu-shares 映射到 cpu.shares
而在 cgroup v2 中,systemd 的 CPUWeight 是独立于 Docker 之外的另一套配置。
混用时要确认你操作的是不是同一个 cgroup 路径。

第四,
修改资源限制后要通过 docker inspect 验证。
执行 docker update 后立即通过 docker stats 观察不一定能看到变化,
因为 CPU 占用数据本身是不断波动的,
正确方式是查看配置项是否真的写入成功。

效果验证怎么做才准确

配置完成后,建议用压力测试工具验证效果。
先在宿主机安装 stress-ng

yum install -y stress-ng   # CentOS/RHEL
apt install -y stress-ng   # Debian/Ubuntu

然后对一个测试容器施加高压力:

docker run -d --name stress-test --cpus="1" --cpu-shares=512 stress-ng --cpu 4 --timeout 120s

同时运行另一个普通容器,再用 systemd-cgtop 观察两个容器的 CPU 分配比例:

systemd-cgtop

正常情况下,
权重较高的容器会获得更多 CPU 时间片,
--cpus="1" 容器即使压力很大,
CPU 占用率也会被限制在 100% 左右,
不会拖垮宿主机其他进程。

常见问题解答

Q:设置了 CPU 权重后,业务容器仍然被其他容器抢占资源,是怎么回事?

先检查宿主机 CPU 是否存在超线程争抢,然后确认两个容器是否都在同一个 cgroup 层级。
建议先给核心业务容器设置 --cpus 硬限制,再用 --cpu-shares 调整权重,两者配合才能达到防抢占效果。

Q:docker update 动态调整后,容器重启配置会丢失吗?

不会丢失。docker update 修改的是容器的 HostConfig,重启容器后配置仍保留。
但如果你是用 docker run 重新创建容器而不是重启,需要重新指定资源参数。

Q:Web 应用容器内存经常接近上限,怎么判断是正常占用还是内存泄漏?

可以结合 docker stats --no-stream 连续观察,如果内存占用持续上升且不回落,且容器内没有缓存类进程,基本可以判断为内存泄漏。
建议先调小内存限制让容器 OOM 重启,再结合日志定位。

Q:有没有更简单的工具能直观看到容器资源抢占情况?

Docker 自带的 docker stats 最直接,可以实时看到每个容器的 CPU、内存、网络 IO。
需要看历史趋势可以用 cAdvisor,更详细的内核级信息可以查看 /sys/fs/cgroup/<容器ID>/cpu.stat 中的 throttled_time 字段,该值持续增长说明容器确实被系统限制过 CPU。

如果你正在处理 Linux 系统资源动态调度容器防止资源抢占,建议先按本文步骤完整执行,再根据自己的环境做微调;
遇到异常时优先回看避坑和高频问题部分。
选云服务器时尽量确认宿主机内核开启了 cgroup v2,目前主流云厂商的新一代云服务器均已默认支持,相关配置建议以你实际购买的服务商控制台和官方文档为准。

分享到:
上一篇
宝塔对接企业微信钉钉实时推送故障告警
下一篇
定时任务自动备份全站数据库与大模型文件的完整教程
1
系统公告

机房迁移升级通知

尊敬的用户: IP 段 103.23.148.x、156.224.29.x 原香港一区线路波动、攻击频繁,平台定于 7 月 5 日凌晨分批迁移至香港 GIA 机房,硬件升级 AMD 铂金机型。 迁移均在凌晨操作,最大程度降低业务影响,迁移期间服务器临时关机; 升级后配置不降低、费用不涨价,数据默认同步迁移; 迁移后 IP 全部更换,请及时修改域名解析、防火墙白名单; 建议提前备份重要数据,有问题可联系在线客服。 感谢理解与支持! 泽御云科技 2026.06.30
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意