vLLM中swap空间耗尽导致并发推理崩溃的解决方案与预防

文章导读
并发推理时进程被系统杀掉,日志里出现“Cannot allocate memory”或“Killed”这类信号,同时系统 swap 占用接近 100%,这种情况在 vLLM 服务里通常不是 vLLM 本身的内存泄漏,而是运行环境给进程分配的 swap 空间不足,或者 vLLM 的显存/内存管理策略与系统内存配置不匹配。最先要判断的方向是:swap 是否被当成了显存溢出的兜底,而不是真正“内存不够用
📋 目录
  1. A 现象与常见误区
  2. B 检查点:先确认崩溃边界
  3. C 处理动作:先止血,再调优
  4. D 验证信号:怎么确认问题已解决
  5. E 预防:避免再触发 swap 极限
A A

并发推理时进程被系统杀掉,日志里出现“Cannot allocate memory”或“Killed”这类信号,同时系统 swap 占用接近 100%,这种情况在 vLLM 服务里通常不是 vLLM 本身的内存泄漏,而是运行环境给进程分配的 swap 空间不足,或者 vLLM 的显存/内存管理策略与系统内存配置不匹配。最先要判断的方向是:swap 是否被当成了显存溢出的兜底,而不是真正“内存不够用”。很多部署把 vLLM 的 GPU 显存利用率设成 0.9 以上,又把 CPU 内存预留得太小,一旦并发请求触发中间张量或 KV cache 的 CPU 拷贝,系统就会用 swap 硬扛,最终被 OOM Killer 终止。

现象与常见误区

vLLM 并发推理崩溃通常表现为:服务日志打印“Killed”或“CUDA error: out of memory”,但用 nvidia-smi 看显存还有剩余;系统层面 free -h 显示 swap 几乎占满,dmesg 能看到 OOM Killer 的痕迹。这里有两个常见误区:第一,把 swap 耗尽当成显存不足去调整 GPU 内存分配,结果显存降了,问题没解决;第二,认为 vLLM 不使用 CPU 内存,所以只盯着显存。事实上,vLLM 在处理 preemption、beam search、并行采样以及部分算子回退时,会在 CPU 内存上暂存张量。并发请求数一高,这些临时内存需求会叠加,占用大量 swap。

检查点:先确认崩溃边界

按下面的顺序检查,每一步都能直接给出下一步动作。不要一上来就改 vLLM 参数,先确认系统资源上限。

  • 检查 OOM 类型:执行 dmesg | tail -50,看是否有“Out of memory: Killed process”。如果有,说明是系统级内存不足,不是 vLLM 内部错误。
  • 检查 swap 配置:执行 free -h,重点看 swap 总量和已用量。如果 swap 总量本身就为 0,那进程会直接被 OOM Killer 杀掉;如果 swap 容量很小,需要看是哪个进程在占用。
  • 检查 vLLM 启动参数:确认 `--gpu-memory-utilization` 和 `--max-num-seqs` 是否同时设置得过高。这两个参数一起决定显存和 CPU 内存的占用上限。
  • 检查并发来源:确认是单个客户端请求触发的崩溃,还是并发请求陡增时崩溃。可以临时限制客户端并发数,看是否复现。

处理动作:先止血,再调优

如果确认是 swap 耗尽导致 OOM,优先做三件事:限制内存占用、增加 swap 缓冲、调整 vLLM 调度参数。动作之间按顺序执行,每步都能验证效果。

1. 限制 vLLM 的 CPU 内存占用

启动 vLLM 时,降低 `--max-num-seqs` 是直接减少并发时 CPU 内存峰值的方法。比如原来设置 256,可以先改成 64。同时可以降低 `--gpu-memory-utilization` 到 0.85 以下,保留更多显存开销余地,减少因显存不足而转移到 CPU 内存的频率。这个动作的验证方式:启动后观察 free -h 中 swap 使用量是否不再持续增长。

2. 调整系统 swap 策略

如果 swap 总量较小,可以考虑增加 swap 文件,但必须明确这是临时的系统级缓冲,不是提升性能的方案。同时调整 swappiness 参数,让它更倾向于回收 page cache 而不是交换匿名内存。可以临时执行:

sudo sysctl vm.swappiness=10

查看当前配置:

cat /proc/sys/vm/swappiness

如果想持久化,需要写到 /etc/sysctl.conf,但要先验证当前值是否合适。这个动作的风险是:过低的 swappiness 在物理内存不足时可能直接触发 OOM,所以只适用于 swap 容量不足但物理内存还有余量的场景。

vLLM中swap空间耗尽导致并发推理崩溃的解决方案与预防

3. 调整 vLLM 的调度与缓存参数

vLLM 默认会把部分 KV cache 存放在 CPU 内存,便于在显存不足时做 swapping。如果系统 CPU 内存本身吃紧,可以关闭或限制这种 CPU swap。通常通过设置较小的 `--cpu-offload-gb` 或者直接不开启 offload 功能来控制。这个参数名可能随版本略有差异,具体可以先查看当前版本的帮助信息:

python -m vllm.entrypoints.openai.api_server `--help` | grep -i swap

如果没有找到相关参数,说明当前版本不支持 CPU swap 控制,那就需要从前两个动作下手。

验证信号:怎么确认问题已解决

修复后的验证不以“服务能跑”为标准,而是要看三件事:swap 使用曲线是否平稳、并发请求是否持续成功、OOM 日志是否消失。可以做一个最小复现片段,用脚本并发发送 20 个推理请求:

for i in $(seq 1 20); do
    curl -s -X POST http://localhost:8000/v1/completions \
        -H "Content-Type: application/json" \
        -d '{"model":"your-model", "prompt":"Hello", "max_tokens":256}' &
done
wait

观察服务是否全部返回。如果仍出现 Killed,执行 dmesg | grep -i oom 确认是否仍为内存问题,然后继续降低并发数或调整资源限制。同时用 watch -n 1 free -h 观察 swap 变化,若请求结束后 swap 被回收,说明系统在正常换页;若 swap 持续保持高位,说明进程仍可能在交换风暴中。

预防:避免再触发 swap 极限

预防的核心是给 vLLM 的 CPU 内存使用留出明确边界。启动容器或 systemd 服务时,可以设置 MemoryLimit 把进程内存限制在物理内存范围内,让 OOM 发生在进程内部而不是系统级别。例如在 systemd service 中配置:

MemoryLimit=8G

如果模型本身需要更大的 CPU 内存,应同步调整 this 限制。需要结合环境确认实际内存占用,建议先用低并发压测 10-30 分钟,记录峰值 RSS,再合理设置。另一个预防点是监控:把 memory.max_usage_in_bytes 和 swap 使用量纳入告警,尽早发现内存爬坡。

这个问题的边界很明确:如果你已经确认随机并发导致 OOM,而显存并未打满,那么核心矛盾不是 GPU 显存,而是 CPU 内存和 swap 的容量规划。先限制并发和 GPU 利用率,再调整系统 swap 策略,最后再考虑 vLLM 的 offload 参数。这样按顺序排查,能最快定位并解决,同时避免把症状当病因去乱调参。