跳到主要内容

CPU 与内存

大模型推理最显眼的硬件通常是 GPU,但 CPU 和系统内存并不是“配角”。
它们影响模型加载、请求处理、tokenizer、调度、RAG 链路、日志监控,以及显存不足时的 offload 能力。

可以先用一句话理解:

GPU 负责主要矩阵计算,CPU 和内存负责把请求、数据、权重和服务流程稳定地喂给 GPU。

如果 CPU 太弱、内存太小、PCIe 拓扑不合理,即使 GPU 很强,也可能出现启动慢、吞吐上不去、延迟抖动、请求排队甚至服务 OOM。

1. CPU 在推理服务中的作用

LLM 推理中的核心计算通常在 GPU 上完成,但一次在线请求并不是只有矩阵乘法。

CPU 常参与这些环节:

  • HTTP / gRPC 请求解析。
  • 鉴权、限流、路由和队列管理。
  • prompt 模板拼接和参数校验。
  • tokenizer 编码和 detokenizer 解码。
  • 推理框架的 batch 调度。
  • 采样逻辑中的部分控制流程。
  • 返回结果拼装、流式输出和日志记录。
  • RAG 场景中的检索、重排、上下文构造。
  • 监控指标、trace、审计和业务侧回调。

因此,GPU 利用率低不一定说明 GPU 不够强,也可能是 CPU 侧没有及时把任务准备好。

常见表现包括:

  • GPU 利用率忽高忽低。
  • 首 token 延迟偏高。
  • 高并发下请求排队,但显存仍有余量。
  • tokenizer 进程或 Web 服务进程 CPU 占用很高。
  • RAG 服务中检索、重排或上下文拼装拖慢整体链路。

2. tokenizer 和请求处理开销

tokenizer 是 CPU 侧非常常见的瓶颈。
用户输入的文本需要先被切分成 token,模型输出 token 后也需要被还原成文本。

tokenizer 开销受这些因素影响:

  • 输入文本长度。
  • 并发请求数。
  • tokenizer 实现是否高效。
  • 是否启用 fast tokenizer。
  • 是否有大量 prompt 模板拼接和字符串处理。
  • 是否在 Python 单进程中串行处理。

对于短输出、强并发的在线服务,tokenizer 和请求调度可能占到相当可观的延迟比例。
如果模型本身很小,或者 GPU 很强,CPU 侧瓶颈会更明显。

优化方向通常包括:

  • 使用高性能 tokenizer 实现。
  • 避免重复 tokenization,对固定系统提示词做缓存。
  • 减少不必要的字符串拼接和 JSON 反复序列化。
  • 将 API 服务、检索服务和推理引擎合理拆分。
  • 给推理服务预留足够 CPU 核数,不要和其他重任务混跑。

3. 系统内存用于什么

系统内存不是显存,但在模型服务中仍然很关键。

系统内存常用于:

  • 模型权重从磁盘加载到进程时的临时占用。
  • 文件系统缓存,加速权重重复读取。
  • CPU offload 的权重或 KV Cache。
  • 多进程推理服务的进程开销。
  • tokenizer、请求队列、日志和监控数据。
  • RAG 检索中的索引、缓存和中间结果。
  • 数据预处理、评测任务和批量任务。

一个容易踩坑的点是:模型最终进入显存,不代表加载过程中完全不吃系统内存。
加载大模型时,权重文件、反序列化过程、框架临时对象、文件缓存都可能让内存瞬间升高。

如果内存不足,可能出现:

  • 模型加载阶段被系统 OOM killer 杀掉。
  • 容器内存限制触发 OOM。
  • 启动速度极慢,系统频繁 swap。
  • 多个模型副本无法同时加载。
  • CPU offload 后延迟严重抖动。

4. CPU offload

CPU offload 指把部分权重、KV Cache 或中间数据放到系统内存中,需要时再通过 PCIe 传回 GPU。

它的主要作用是缓解显存不足:

显存放不下
-> 一部分数据放到系统内存
-> 计算时再搬到 GPU

offload 可以让模型“勉强跑起来”,但通常会牺牲速度。
原因是系统内存到 GPU 显存之间要经过 PCIe,带宽和延迟都远不如 GPU 本地显存。

适合使用 offload 的场景:

  • 本地实验,目标是能跑而不是高吞吐。
  • 偶尔加载比显存略大的模型。
  • 低并发、低 QPS 的内部工具。
  • 临时验证模型效果。

不适合作为主要方案的场景:

  • 在线高并发服务。
  • 严格低延迟服务。
  • 长上下文、大 batch 推理。
  • 已经对吞吐和稳定性有明确 SLA 的生产服务。

实践中可以记住:offload 是兜底手段,不是免费的显存扩展。

5. NUMA 为什么重要

NUMA 是 Non-Uniform Memory Access 的缩写。
在多路 CPU 服务器上,不同 CPU socket 连接着不同内存通道和 PCIe 设备。一个进程访问“本地”内存会更快,访问另一个 socket 下的内存会更慢。

在 GPU 服务器中,NUMA 会影响:

  • CPU 线程访问内存的延迟。
  • CPU 到 GPU 的 PCIe 路径。
  • 多卡服务的跨 socket 数据传输。
  • 网络卡、存储卡、GPU 之间的数据路径。

例如,一张 GPU 接在 CPU 0 的 PCIe root complex 下,但推理进程主要跑在 CPU 1 上,就可能产生跨 NUMA 访问。
这类问题不一定让服务直接失败,但可能导致延迟抖动和吞吐下降。

排查时可以关注:

  • GPU 与 CPU socket 的拓扑关系。
  • 推理进程绑定在哪些 CPU 核上。
  • 内存分配是否靠近使用它的 CPU / GPU。
  • 多卡是否跨 socket 通信。
  • 网卡是否和目标 GPU 在同一侧拓扑上。

常用思路是让服务进程、CPU 线程、内存分配和目标 GPU 尽量处在同一个 NUMA 节点附近。

6. PCIe root complex 和拓扑

PCIe root complex 可以理解为 CPU 侧连接 PCIe 设备的入口。GPU、网卡、NVMe 等设备都挂在不同的 PCIe 拓扑下面。

这会影响:

  • CPU 到 GPU 的数据传输。
  • GPU 之间通过 PCIe 通信的路径。
  • GPU 与网卡之间的数据路径。
  • 多卡并行时的通信均衡性。
  • 存储加载模型到 GPU 的路径。

同一台机器里,几张 GPU 不一定完全等价。
有的 GPU 之间路径更近,有的需要跨 CPU socket,有的与高速网卡更近。

在单机多卡或多机推理中,需要特别注意:

  • tensor parallel 的 GPU 是否拓扑相近。
  • 高速网卡是否靠近参与通信的 GPU。
  • NVMe 是否会和 GPU/网卡争用 PCIe 带宽。
  • 推理框架选择的 GPU 编号是否符合实际拓扑。

当服务出现“某些卡更慢”“多卡扩展不线性”“跨节点延迟高”时,PCIe 和 NUMA 拓扑都应该纳入排查范围。

7. CPU 推理与 GPU 推理的区别

CPU 也可以跑大模型,尤其是量化模型、本地工具和低并发场景。
但 CPU 推理和 GPU 推理的优势不同。

对比项CPU 推理GPU 推理
主要优势成本低、部署简单、内存容量大矩阵计算强、吞吐高、延迟低
常见场景本地实验、小模型、低频调用在线服务、高并发、长上下文
主要瓶颈内存带宽、向量化能力、线程调度显存容量、显存带宽、调度效率
模型精度常见 INT4 / INT8 量化FP16 / BF16 / FP8 / INT8 / INT4
扩展方式增加 CPU 核数和内存带宽增加 GPU、显存和互联能力

CPU 推理并不等于不能用。
如果是 7B 以下量化模型、个人助手、离线批处理、边缘设备或内网低频工具,CPU 推理可能足够。

但如果目标是多人并发、低延迟、长上下文或稳定在线服务,GPU 通常更合适。

8. 内存带宽对本地推理的影响

LLM 推理不是只看 CPU 核数。
对于 CPU 本地推理,内存带宽往往非常关键,因为模型权重需要不断从内存中读取。

可以粗略理解为:

每生成一个 token,都要大量读取模型权重。
内存带宽越高,权重读取越快,token 生成速度越容易提升。

这也是为什么有时“核心很多”不一定快。
如果内存通道少、内存频率低、带宽不足,更多 CPU 线程也可能只是互相争抢内存带宽。

影响 CPU 推理速度的因素包括:

  • 内存通道数量。
  • DDR4 / DDR5 / LPDDR / HBM 等内存类型。
  • 内存频率和实际带宽。
  • CPU SIMD 指令集能力。
  • 量化格式和推理后端优化。
  • 线程数设置是否合理。
  • NUMA 绑定是否正确。

本地 CPU 推理选机器时,不要只看“几核几线程”,还要看内存带宽和推理后端是否适配。

9. CPU / 内存选型建议

不同场景下,CPU 和内存的关注点不同。

场景CPU 建议内存建议
本地学习和实验普通多核 CPU 即可,优先保证兼容性至少能容纳模型文件、运行时和系统开销
单卡 GPU 推理给 API、tokenizer、调度和监控预留足够核心通常建议大于模型权重文件体积,并留出加载冗余
多卡 GPU 推理关注 PCIe 通道、NUMA、线程绑定和调度开销需要支撑多副本加载、文件缓存和服务进程
CPU 本地推理关注 SIMD、核心数、内存带宽和线程调度优先看内存带宽,其次看容量
RAG + LLM 服务CPU 还要承担检索、重排、JSON 处理和业务逻辑需要容纳索引、缓存、请求队列和模型服务开销
生产在线服务选择服务器级 CPU,避免和重型批任务混部避免内存打满,预留监控、日志和峰值空间

一个实用原则是:

先保证内存够,再看 CPU 是否会卡住请求处理,最后结合拓扑优化多卡和网络路径。

粗略建议:

  • 不要让系统长期处在高 swap 状态。
  • 不要把 CPU 核数全部压给无关任务,推理服务需要调度余量。
  • 大模型加载时给系统内存留出明显冗余。
  • 使用 CPU offload 时,系统内存要远大于 offload 量。
  • 多卡服务器优先确认 NUMA、PCIe、GPU 和网卡拓扑。
  • RAG 服务要把向量库、重排模型和业务服务的 CPU / 内存一起算进去。

10. 常见问题排查

GPU 很空,但服务很慢

可能原因:

  • tokenizer 或请求处理成为瓶颈。
  • batch 调度不合理。
  • RAG 检索链路慢。
  • CPU 核数不足或被其他进程抢占。
  • Python 服务单进程串行处理过多逻辑。

模型加载时直接 OOM

可能原因:

  • 系统内存不足。
  • 容器内存限制太小。
  • 权重加载存在临时峰值。
  • 同时启动多个模型副本。
  • 文件缓存、日志或其他进程占用了大量内存。

开启 CPU offload 后能跑但很慢

可能原因:

  • PCIe 传输成为瓶颈。
  • offload 数据量太大。
  • 请求并发或上下文长度太高。
  • CPU 内存带宽不足。
  • NUMA 绑定不合理,产生跨 socket 访问。

多卡服务有的卡快有的卡慢

可能原因:

  • GPU 拓扑不均衡。
  • GPU 跨 PCIe root complex 或跨 NUMA 节点。
  • 网卡和目标 GPU 距离较远。
  • 推理框架选择的 GPU 编号不符合物理拓扑。
  • 某些卡还被其他任务占用。

11. 总结

CPU 和内存不会替代 GPU,但会决定 GPU 能不能被稳定、高效地使用。

可以按这个顺序判断主机资源:

  1. 系统内存是否足够加载模型、承载缓存和服务进程。
  2. CPU 是否足够处理 tokenizer、请求调度、RAG 和业务逻辑。
  3. CPU、内存、GPU、网卡和 NVMe 的拓扑是否合理。
  4. 是否依赖 CPU offload,如果依赖,就要接受明显性能损耗。
  5. 是否有监控能看到 CPU、内存、swap、NUMA 和 PCIe 相关瓶颈。

真正做硬件选型时,不要只问“GPU 够不够”。
更可靠的方式是把模型规模、并发、上下文长度、推理框架、RAG 链路和服务部署方式一起看,再反推 CPU、内存、GPU、存储和网络。