服务器 OS 过去 20 年都是为 CPU + 网卡 + 磁盘设计的。AI 时代加进来了 GPU、NPU、HBM、NVLink 这些新东西——OS 需要适配。本文从 GPU 调度讲到大模型训练 OS 优化。
AI 时代 OS 的新挑战
graph TB
TRAD[传统服务器 OS]
TRAD --> T1[CPU 调度]
TRAD --> T2[内存管理]
TRAD --> T3[文件 / 网络 IO]
AI[AI 时代追加]
AI --> A1[GPU / NPU 调度]
AI --> A2[HBM 内存管理]
AI --> A3[GPUDirect / NVLink]
AI --> A4[NUMA + GPU 拓扑]
AI --> A5[大量 IO(数据集 / checkpoint)]
AI --> A6[超大进程地址空间]
GPU 设备文件
NVIDIA GPU 在 Linux 下表现为字符设备:
1 2 3 4 5 6 7 8 9 10 11 12
| ls -la /dev/nvidia*
ls /dev/dri/
|
容器里要把这些设备 mount 进去——nvidia-container-toolkit 自动做这件事:
1 2 3 4 5 6 7 8 9 10 11 12
| docker run --gpus all nvidia/cuda:12.4-base nvidia-smi docker run --gpus '"device=0,1"' ...
kubectl describe node <node>
resources: limits: nvidia.com/gpu: 1
|
GPU 资源在 K8s 里的模型
graph TB
PLUGIN[nvidia-device-plugin
DaemonSet]
PLUGIN --> EXPOSE[暴露 nvidia.com/gpu 资源]
EXPOSE --> SCHED[K8s Scheduler
按 GPU 数量调度]
SCHED --> POD[Pod 申请 GPU]
POD --> RUNTIME[nvidia-container-runtime
映射设备]
这个模型有几个根本问题:
1 2 3 4 5 6 7 8 9
| 1. 整数粒度: 一个 Pod 只能要 1/2/4/8 个 GPU → 小模型推理浪费 GPU 资源
2. 单 GPU 不可分享: → 一个 Pod 占整张卡 3. 没有拓扑感知: → 8 GPU Pod 可能跨 NUMA → NCCL 性能受影响
|
GPU 资源细分:MIG / vGPU / Time-Slicing
第 7.2 已经讲过——这里讲 K8s 层适配:
graph TB
GPU[GPU 资源细分]
GPU --> MIG[NVIDIA MIG
硬件级]
GPU --> VGPU[NVIDIA vGPU
软件许可]
GPU --> TS[Time-Slicing
K8s 软件]
GPU --> MPS[CUDA MPS
进程级]
MIG(A100/H100)
1 2 3 4 5 6 7 8
| nvidia-smi -i 0 -mig 1 nvidia-smi mig -cgi 9,9,9
nvidia.com/mig-1g.10gb nvidia.com/mig-2g.20gb nvidia.com/mig-3g.40gb
|
MIG 后每个实例独立显存、SM、L2 缓存——真正的硬件隔离。
Time-Slicing
1 2 3 4 5 6 7 8 9
| nvidia-device-plugin 配置: sharing: timeSlicing: replicas: 4 # 每张 GPU 切成 4 份
K8s 看到: 8 GPU 节点 → 32 个 nvidia.com/gpu
适合: 推理 / 开发 不适合: 训练(互相抢,性能不可预测)
|
CUDA MPS(Multi-Process Service)
1 2 3 4 5
| MPS: 多个 CUDA 进程共享一张 GPU 启用: nvidia-cuda-mps-control -d 应用: HPC 多进程任务
K8s 集成: 部分插件支持
|
NVIDIA GPU Operator
K8s 上 GPU 全栈管理:
1 2 3 4 5 6 7
| nvidia-gpu-operator 包含: - Driver Container(容器化驱动) - Device Plugin - DCGM Exporter(监控) - GPU Feature Discovery(标签) - MIG Manager - Network Operator(GPUDirect)
|
一键部署整个 GPU stack——但有性能开销和 license 复杂度。
NUMA-aware 调度:GPU 拓扑
8 GPU 服务器 GPU ↔ CPU 的拓扑:
graph TB
CPU0[CPU Socket 0
NUMA 0] --- PCIe0[PCIe Switch 0]
CPU1[CPU Socket 1
NUMA 1] --- PCIe1[PCIe Switch 1]
PCIe0 --- G0[GPU 0] & G1[GPU 1] & G2[GPU 2] & G3[GPU 3]
PCIe1 --- G4[GPU 4] & G5[GPU 5] & G6[GPU 6] & G7[GPU 7]
G0 ---|NVLink| G4
G1 ---|NVLink| G5
...
1 2 3 4 5 6 7 8 9 10
| nvidia-smi topo -m
|
调度的智慧:
1 2 3
| - DataLoader 进程绑到 GPU 同侧 NUMA 的 CPU 上 - 内存分配也要 NUMA-bind - 否则 PCIe 跨 socket 性能崩 30-50%
|
CPU pinning for AI
1 2 3 4 5 6 7 8 9
| import os import torch
os.sched_setaffinity(0, {0, 1, 2, 3, 4, 5, 6, 7})
|
1 2 3 4 5
| docker run --cpuset-cpus=0-15 --cpuset-mems=0 ...
kubelet --topology-manager-policy=single-numa-node
|
K8s 1.18+ 支持 Topology Manager——同时考虑 CPU + GPU + 网卡的 NUMA 亲和。
GPUDirect 在 OS 层
GPUDirect RDMA 让网卡直接读写 GPU 显存——OS 要做的事:
1 2 3 4 5 6 7 8 9 10 11 12
| 1. peer_mem 模块加载: modprobe nvidia_peermem 2. GPU BAR 暴露给 PCIe peer-to-peer: # nvidia-smi -q | grep -i bar 3. PCIe ACS 关闭: # 否则 ACS 阻断 P2P setpci -s <BDF> ECAP_ACS+0x6.w=0:1f0
4. IOMMU 设置: intel_iommu=on iommu=pt # passthrough 模式
|
GPUDirect Storage(GDS)
GPU 直接读 NVMe:
1 2 3 4 5 6 7 8 9 10
| GDS: - cuFile API - 绕过 CPU 内存 - 大数据集训练加速 - PyTorch / NVIDIA DALI 支持
要求: - NVIDIA MOFED 驱动 - GPU + NVMe 在同一 PCIe Switch(理想) - 内核 5.x+
|
OS 对 HBM 的态度
GPU 显存(HBM)是不归 Linux 内核管的:
1 2 3 4 5 6 7 8 9 10
| Linux 看到: 主机 DRAM GPU 显存: 由 NVIDIA driver / CUDA Runtime 管 - cudaMalloc - 不在 vmstat / free 里显示 - nvidia-smi 看 Unified Memory(CUDA UM): - 假装 CPU/GPU 共用内存 - 实际是 driver 在背后搬数据 - 大模型训练用得少(性能不可控)
|
CXL 时代会改变这个——未来 GPU 显存可能”挂到 CPU 主存空间”:
1 2 3 4 5 6 7
| CXL Type 3 远端内存设备: - 暴露成普通 NUMA 节点 - Linux 直接 mmap
CXL 上挂 HBM: - 实验性,B200 后可能 - 会改变 OS 对显存的认知
|
大文件 / 大内存:调优
大模型训练对 OS 的特殊压力:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 模型权重文件: Llama 70B FP16 = 140 GB GPT-3 175B = 350 GB → 单文件超过 100 GB 是常态 ext4 / XFS 都没问题,但读写要: - 大块 IO(≥ 1 MB) - O_DIRECT 跳过 page cache - 多线程并行
进程地址空间: PyTorch 训练进程: 1-2 TB 虚拟内存 Linux 默认 64 TB 上限够用 mmap 支持: CUDA Runtime 用 mmap 管 page-locked memory vm.max_map_count 要调大: sysctl vm.max_map_count=1048576
|
训练专用的 K8s 调度
1 2 3 4 5 6 7 8 9 10
| 普通 K8s scheduler 缺陷: - 不懂 gang scheduling(几十个 Pod 要"全部启动 OR 不启动") - 不懂拓扑(同 Pod 的 GPU 应该 NVLink 互联) - 不懂训练队列优先级
AI 专用调度器: Volcano(华为 + 社区): gang scheduling Yunikorn: Apache 的多租户 KAI Scheduler(NVIDIA Run.ai): GPU 池化 Kueue(K8s 官方): Job Queueing
|
Gang Scheduling
1 2 3 4 5 6 7 8 9 10 11 12
| 传统 K8s: 一次调一个 Pod Gang: 一组 Pod 必须同时调度
应用: - 分布式训练(128 个 worker 必须一起启) - MPI 作业 - RAY / Dask 集群
不 gang scheduling 时: - 部分 Pod 已启动,等其他 - 占资源不释放 - 集群死锁
|
训练相关的内核参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| sysctl kernel.shmmax=1099511627776 echo "16G" > /sys/fs/cgroup/<group>/shm.size
ulimit -n 1048576 echo "* soft nofile 1048576" >> /etc/security/limits.conf echo "* hard nofile 1048576" >> /etc/security/limits.conf
ulimit -u unlimited echo "* soft nproc unlimited" >> /etc/security/limits.conf
ulimit -l unlimited echo "* soft memlock unlimited" >> /etc/security/limits.conf echo "* hard memlock unlimited" >> /etc/security/limits.conf
vm.nr_hugepages = 8192
net.core.rmem_max = 268435456 net.core.wmem_max = 268435456 net.core.netdev_max_backlog = 30000
|
NPU 调度:昇腾 / 寒武纪等
国产 NPU 的 OS 适配:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 华为昇腾(Ascend): - /dev/davinci0 ~ N - npu-smi 工具 - K8s ascend-device-plugin - resources.limits: huawei.com/Ascend910
寒武纪(Cambricon): - /dev/cambricon_dev* - cnmon 工具 - K8s cambricon-device-plugin - resources.limits: cambricon.com/mlu
摩尔线程: - /dev/mtgpu* - mthreads-gmi - K8s mthreads-device-plugin
各家 device-plugin 仿照 NVIDIA 风格,但生态成熟度差异大。
|
checkpoint / 断点续训
大模型训练常见操作——对 OS IO 子系统的考验:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| checkpoint 写入: - 70B FP16 模型: ~140 GB - 训练优化器状态: 280-400 GB - 激活值 / 元数据: 几十 GB - 总: 500 GB - 1 TB / checkpoint - 频率: 每 1-2 小时一次
要求: - 高速文件系统: Lustre / WekaFS / GPFS - 网络足够(万卡级用 InfiniBand 写) - 所有 GPU 同时写 → 集合 IO
故障恢复: - 节点挂了 → 训练框架自动从最近 checkpoint 恢复 - PyTorch FSDP / DeepSpeed 都有此能力 - SLA: 一次故障 < 30 分钟恢复
|
监控:DCGM / Prometheus
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| DCGM(Data Center GPU Manager): - NVIDIA 官方 GPU 监控 - dcgm-exporter 暴露 Prometheus 格式 - 关键指标: GPU 利用率、显存、温度、功耗、ECC 错误 Prometheus + Grafana: - dcgm-exporter - node-exporter - kube-state-metrics - 一图看全集群
DCGM 监控万卡集群: - 每秒几万 metric - 异常自动告警 - 故障节点自动隔离
|
容器与 GPU 的几个老坑
坑 1:容器里看不到 nvidia-smi
1 2 3 4 5 6 7
| apt install nvidia-container-toolkit
dnf install nvidia-container-toolkit
systemctl restart docker
|
坑 2:CUDA 版本不匹配
1 2 3 4 5
| Host driver 版本必须 ≥ Container 内 CUDA 版本 查看: nvidia-smi(看左上角 CUDA Version)
Host driver 535 → 兼容 CUDA 12.x Host driver 470 → 仅兼容 CUDA 11.x
|
坑 3:MIG 实例不可见
1 2 3 4 5
| MIG 启用后,容器要明确请求 MIG 实例: resources.limits: nvidia.com/mig-1g.10gb: 1 不能再用 nvidia.com/gpu: 1(除非禁 MIG)
|
坑 4:训练 Pod OOM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 显存 OOM: batch size / sequence length 太大 主机内存 OOM: DataLoader workers 太多 SHM 不够: /dev/shm 默认 64 MB,DataLoader 经常需要更大
K8s 调大 SHM: spec: containers: - volumeMounts: - mountPath: /dev/shm name: dshm volumes: - name: dshm emptyDir: medium: Memory sizeLimit: 16Gi
|
坑 5:跨 NUMA 性能损失
1 2 3 4 5 6 7 8
| 8 GPU Pod 没有 numa-aware 调度: - 跨 socket PCIe 通信 - DataLoader CPU 在另一个 NUMA - 实测性能损失 20-40%
解决: - 启用 K8s Topology Manager - 训练框架显式 numactl
|
坑 6:NCCL 启动失败
1 2 3 4 5 6 7
| 症状: "NCCL WARN Failed to open socket" 常见原因: - SHM 太小 - ulimit -l(memlock)太小 - IB 设备不可见 - PCIe ACS 没关 - Container 没 IPC=host
|
坑 7:GPU 假性死机
1 2 3 4 5
| GPU "stuck" 但 nvidia-smi 还能查: - dmesg | grep "Xid" → 看 NVIDIA Xid 错误 - Xid 13/31/63/79:通常硬件 / 散热问题 - 重启 GPU:nvidia-smi --gpu-reset -i <id> - 持续: 更换 GPU
|
大模型训练时 OS 实战清单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| fs.file-max = 2097152 fs.aio-max-nr = 1048576 kernel.shmmax = 1099511627776 kernel.shmall = 268435456 vm.max_map_count = 1048576 vm.swappiness = 10 vm.dirty_ratio = 5 vm.dirty_background_ratio = 2 net.core.rmem_max = 268435456 net.core.wmem_max = 268435456 net.core.netdev_max_backlog = 30000
* soft nofile 1048576 * hard nofile 1048576 * soft nproc unlimited * hard nproc unlimited * soft memlock unlimited * hard memlock unlimited
intel_iommu=on iommu=pt default_hugepagesz=2M hugepagesz=2M hugepages=8192 nohz_full=8-31 isolcpus=8-31 nosoftlockup mitigations=off
|
OS 在 AI 集群的角色变化
graph TB
OLD[传统 OS]
OLD --> O1[管理 CPU/MEM/IO]
NEW[AI 集群 OS]
NEW --> N1[GPU 调度 + 拓扑]
NEW --> N2[NUMA + GPU 联合调度]
NEW --> N3[大文件 IO + checkpoint]
NEW --> N4[InfiniBand + RDMA]
NEW --> N5[BPF observability]
NEW --> N6[Container + K8s 集成]
一些数字直觉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| nvidia-driver 升级: - 大版本(535→555): 需重启 - 同版本小修: 有时 modprobe 即可
GPU "ready" 时间: - 节点重启: 5-10 分钟(初始化) - 容器调度后启动: 5-30 秒
GPU 利用率监控: - dcgm 1 秒采样 - K8s prometheus 15 秒间隔 - 8 GPU 节点: 生成 ~50 个 metric / 秒
万卡集群 OS 配置一致性: - Ansible / Salt: 5-30 分钟 - 配置漂移检测: 必备
|
国产 OS 的 AI 适配
1 2 3 4 5 6 7 8 9 10 11 12
| openEuler: - 与昇腾深度集成 - npu-smi、ascend-device-plugin 已包 - "openEuler AI 版"
龙蜥(Anolis OS): - 与寒武纪 / 摩尔线程适配 - SIG-AI 工作组
麒麟(Kylin): - 商用支持华为昇腾 - 政企信创主流
|
待补充:国产 OS 在大模型训练集群的实际部署。
小结
- AI 时代 OS 要管的多了: GPU/NPU 调度、NUMA + GPU 拓扑、大 IO
- nvidia-device-plugin + GPU Operator 是 K8s 标配
- MIG / vGPU / Time-Slicing 是 GPU 资源细分手段
- Volcano / KAI Scheduler 是训练专用调度器
- GPUDirect / GDS 让网卡 / 存储直接访问 GPU 显存
- 大模型训练对 OS 内核参数(SHM / memlock / file-max)有特殊要求
- 国产 OS 已与昇腾 / 寒武纪深度适配
下一篇讲国产服务器 OS——欧拉、麒麟、龙蜥、统信、深度等。