
在一次大模型部署实践中,我们的香港物理服务器频繁出现 GPU 占用率不均、内存频繁 Page Fault、模型初始化异常缓慢等问题。深究之后我发现,虽然这台服务器拥有双路 Intel 至强 CPU 和多张 NVIDIA A100 卡,但因为 NUMA 拓扑未合理绑定,CPU 与 GPU 资源调度混乱,最终导致资源复用效率低下。在本文中,我将分享我如何结合 NUMA CPU 亲和绑定 + GPU 显存隔离 的方式,实现高效的大模型多实例部署。
一、部署环境概况
我所操作的服务器配置如下,位于香港机房,连接至内地和东南亚区域的 AI 服务网关:
- CPU:Dual Intel Xeon Gold 6338 (32C64T x 2)
- 内存:1TB DDR4 ECC RDIMM(每路 CPU 各 512GB)
- GPU:4 x NVIDIA A100 80GB PCIe
- 系统:Ubuntu 22.04 LTS + CUDA 12.1 + PyTorch 2.x
- NUMA 节点数:2
- 使用场景:多模型实例部署(LLM 推理服务 + 图像生成服务共存)
二、面临的问题
默认部署情况下,我们遇到以下典型问题:
- 模型初始化卡顿:多个模型实例启动时集中访问 NUMA node 0 内存;
- GPU 显存浪费:多进程共用 GPU0,但其他 GPU 长时间闲置;
- CPU/GPU 互联带宽瓶颈:跨 NUMA node 访问 PCIe GPU 时,latency 显著上升;
- 资源复用率低:A100 的多实例 CUDA Context 未被合理拆分,服务之间互相抢资源。
三、解决方案概览
我们采用如下策略:
- NUMA + CPU Affinity:使用 numactl 为模型服务进程绑定 CPU + 内存节点;
- GPU 进程隔离:为每个服务进程明确指定 GPU ID,避免 GPU 多进程争抢;
- CUDA MPS 或 MIG 模式(可选):细粒度拆分 GPU 实例,提高并发复用;
- Systemd + Taskset 集成调度:写入服务启动脚本中,保证每次部署都自动绑定。
四、NUMA 拓扑分析
使用 lscpu 与 nvidia-smi topo -m 获取服务器硬件绑定关系:
lscpu | grep NUMA
# NUMA node0 CPU(s): 0-31
# NUMA node1 CPU(s): 32-63
nvidia-smi topo -m
# GPU0 - CPU Affinity: 0-31
# GPU1 - CPU Affinity: 0-31
# GPU2 - CPU Affinity: 32-63
# GPU3 - CPU Affinity: 32-63
观察到 GPU0/1 属于 NUMA node0,GPU2/3 属于 NUMA node1。
五、部署方式实操详解
5.1 NUMA 绑定 PyTorch 模型服务
假设我们要在该服务器上部署两个大模型:
- llm_server.py 使用 GPU0(NUMA node 0)
- image_server.py 使用 GPU2(NUMA node 1)
启动 llm_server.py(绑定 GPU0,NUMA node0)
CUDA_VISIBLE_DEVICES=0 \
numactl --physcpubind=0-31 --membind=0 \
python3 llm_server.py --port 8000
启动 image_server.py(绑定 GPU2,NUMA node1)
CUDA_VISIBLE_DEVICES=2 \
numactl --physcpubind=32-63 --membind=1 \
python3 image_server.py --port 8001
这种方式保证每个服务只使用一个 NUMA 节点的 CPU 与 GPU,不跨节点访问内存或 PCIe,带宽利用最优。
5.2 Systemd 服务注册配置(实现自动绑定)
为了方便服务在重启后自动绑定资源,我将上面命令封装为 systemd service:
[Unit]
Description=LLM Service with NUMA/GPU Binding
After=network.target
[Service]
ExecStart=/usr/bin/numactl --physcpubind=0-31 --membind=0 \
/usr/bin/env CUDA_VISIBLE_DEVICES=0 python3 /opt/llm_server.py
Restart=always
CPUAffinity=0-31
MemoryPolicy=preferred
LimitMEMLOCK=infinity
[Install]
WantedBy=multi-user.target
部署后 systemctl enable llm.service && systemctl start llm.service 即可生效。
5.3 GPU 显存隔离(基于 CUDA MPS)
若模型为轻量推理任务,希望共享 GPU,但限制每个进程使用 20GB 显存,可以启用 MPS Server:
export CUDA_VISIBLE_DEVICES=0
nvidia-cuda-mps-control -d
# 设置显存限制
echo "set_default_active_thread_percentage 40" | nvidia-cuda-mps-control
或者 NVIDIA MIG 模式进行硬件层划分:
nvidia-smi mig -i 0 -cgi 19,19,19,19 -C
# 创建4个 20GB GPU 实例,用于多模型绑定
六、资源复用提升效果评估
我们在部署前后进行了如下性能对比测试:
| 指标 | 优化前 | NUMA + GPU 绑定后 |
|---|---|---|
| LLM 启动时延(秒) | 36.2 | 18.5 |
| GPU 显存利用率 | 不均,GPU0饱和 | 平衡分配,各用1张 |
| 内存跨 NUMA 访问比例 | 42% | <2% |
| CPU 上下文切换(ctx/s) | 12w+ | <2w |
| 总吞吐 QPS(混合请求测试) | 540 | 890 |
七、结语与最佳实践建议
这次实践让我深刻意识到,在大模型多实例部署中,CPU NUMA 与 GPU 拓扑的亲和性匹配至关重要。如果我们只关注 GPU 性能而忽略 CPU/GPU 跨 NUMA 访问成本,很容易造成资源浪费甚至模型不稳定。建议在香港物理服务器中部署大模型服务时,提前梳理拓扑,结合 numactl、CUDA_VISIBLE_DEVICES、MIG/MPS 实现资源可控隔离,最大化服务器算力。











