2026-10-27 · 深度笔记

RAG 系统上云:检索服务和推理服务要不要放同一台机器

一套 RAG 拆成"检索+推理"两台机器后延迟反而更高。这篇记录我改回同机的原因,以及哪些信号说明你确实该拆开。

云主机AI工程RAG架构

先说结论,不是所有 RAG 都值得把检索和推理拆开。

我维护的一个知识库问答系统,初期是"一台 GPU 机器跑推理,旁边再起一台 4 核 8G 跑向量库"。架构图画得很漂亮,两个服务互相独立,将来还能各自扩缩容。上线之后 P95 延迟反而从 1.8 秒涨到 3.4 秒。

后来我把两套服务合回一台机器,延迟回到 2 秒以内,还省了一台机器。下面是我当时算的账。

拆开之后多出来的开销在哪

那 3.4 秒我一段一段量过:

环节耗时说明
推理生成1.5s两台机器都一样
跨机传 chunk~40ms每次 5-8 个片段,几十 KB
序列化与反序列化~10msJSON
推理服务排队1.1s真正的元凶

排队那 1.1 秒不在向量库里,在推理服务里。原因是我把检索做成了同步阻塞调用:HTTP 请求进去,向量库算完返回,推理才开始拿下一段数据。整条链路是串行的。

这账我一开始算错了。拆机器省下的是故障隔离和独立扩容的潜力,多付的是每次请求多一次跨机往返 + 多一次串行等待。并发上不去的时候,这个交换纯亏。

反直觉的地方:GPU 机器的 CPU 大部分是闲的

我对这件事的认知偏差挺大,默认"推理机器 = GPU 机器 = CPU 跑满"。

实际跑一个 7B 模型做生成,GPU 在算的那几秒里 CPU 基本在等。真正吃 CPU 的是它前后的准备工作:

HNSW 查一百万条向量,单次查询的 CPU 时间在毫秒级,这个量级完全塞得进 GPU 推理的间隙里。

所以同机的真实收益不是"少一台机器",是把串行变成并行——GPU 在算第 N 个 token 的时候,CPU 可以同时算第 N+1 个请求的向量检索和 embedding。

我后来在同一台 16 核机器上实测了两种形态:

部署方式QPSP50P95
同机,8+8 核划分111.7s2.9s
两台 8 核机器82.2s4.6s

同机部署有一个必须踩过才知道的坑

挪到同一台机器之后,推理服务的 P99 突然从 3 秒涨到 11 秒,而且不是一直这样——机器重启后那十几分钟特别慢,之后自己就好了。

我一开始完全不知道往哪查,以为是网络抖动。

翻了两天日志才发现:HNSW 的索引文件被推理服务加载模型权重时的内存读冲出了 page cache。

向量库用 mmap 加载索引,索引文件在磁盘上,靠操作系统缓存加速。加载一次模型要读几十 GB 权重,Linux 的 page cache 被冲刷,HNSW 查询就得真去读磁盘。

这个坑的特征是平时没事、加载模型那会儿出事,因为权重加载只发生在启动那一刻,之后缓存慢慢回暖就又好了。所以线上表现是"重启后一段时间特别慢然后自己好了",非常容易被当成玄学。

解决有三条,我按这个顺序用:

什么时候确实该拆

不是所有场景都该同机。我用三条判断,满足两条就拆:

第一,检索侧的内存和推理侧抢同一台机器。 一百万条 1024 维 float32 向量本身就是 4GB,加上 HNSW 的图结构还要往上走一截。两块内存加模型权重挤在同一台机器上,OOM killer 就开始挑人下手,而且它挑谁不挑谁完全看当时的内存快照。

第二,检索和推理的负载曲线完全不同。 白天问答高峰、晚上批量灌库——拆开能省钱,检索那台缩到最小规格,推理那台上 GPU。

第三,故障隔离真的有价值。 向量库挂了的时候,我希望 RAG 降级成"没有检索的问答",而不是整个接口 503。

折中的做法我最后固定成:同一台物理机,两个容器,但用 cgroup 把核数划死。

services:
  llm:
    image: vllm/vllm-openai:latest
    deploy:
      resources:
        limits:
          cpus: "8.0"
          memory: 48G
  vector:
    image: qdrant/qdrant:latest
    deploy:
      resources:
        limits:
          cpus: "8.0"
          memory: 32G

划死核数比给一个 cpus: "1.0" 这种软限制重要得多。软限制下两个容器照样互相抢,只是抢得没那么凶;硬划之后至少能保证推理服务永远拿得到 8 个核。

我自己记下来的判断顺序

最后提一句,上面这些 QPS 和延迟是我自己那台机器上的量级,不是厂商的承诺值。实例规格、带宽单价这类东西变动比软件快得多,还是以各家官方页面为准。

接着读