你的 SaaS 产品以十个设计客户的规模上线,一切运转完美。随后你陆续接入了一百个租户,其中一个——一位在复杂研究工作流中使用 20 万 token 上下文窗口的重度用户——导致了所有其他客户的延迟飙升。支持工单开始涌来。你查看监控面板,却看不到任何明显异常:模型健康,API 返回 200,p50 延迟看起来正常。而你的 p95 已经悄悄翻了三倍。
这就是嘈杂邻居问题,它对 LLM 基础设施的冲击比几乎任何其他共享系统都要剧烈。以下是它为何比数据库场景更难解决——以及真正有效的应对方案。
为何 LLM 打破了多租户的基本假设
传统多租户基础设施拥有数十年的工具积累:连接池、行级安全、每 schema 独立数据库、VPC。所有这些方案的核心抽象都是:每次请求的资源消耗是有上限且大致可预测的。一次数据库查询耗时几毫秒,一次 Web 请求消耗几百微秒的 CPU。你可以根据请求速率来估算容量。
LLM 请求彻底打破了这一假设。单次推理调用可能消耗 512 个 token,也可能消耗 200,000 个。它可能在 300ms 内返回,也可能在复杂的多步骤链路中耗时四分钟。一个 Llama-3 70B 模型上单次长上下文会话的 KV 缓存可能超过 40GB——这些内存必须在整个会话期间驻留在 GPU 上。一块能服务 50 个并发短上下文用户的 GPU,可能被两个运行扩展研究工作流的用户完全占满。
这种变异性并非可以通过工程手段规避的缺陷——它是 LLM 有用性的根本所在。同一套基础设施既要处理简单的问答,也要处理文档分析和多轮 Agent 工作流。而这些工作负载落在同一硬件上。
故障模式在爆发前是隐形的。某个租户的高消耗会话驱逐了另一个租户的 KV 缓存,迫使重新计算。重新计算导致首 token 时间飙升。用户看到卡顿。你的监控显示 GPU 很忙——技术上准确,但对于诊断谁的会话消耗了谁的资源毫无帮助。
基于 Token 的速率限制不是可选项
大多数团队从每分钟请求数(RPM)限制起步。这很容易实现,并能立即阻止最严重的滥用。但它无法解决嘈杂邻居问题,因为请求并不等价。一个发送 100 次短文本分类请求的租户,和一个发送 3 次各含 5 万 token 上下文的请求的租户,对 GPU 的占用完全不同。
LLM 速率限制的正确原语是每分钟 token 数(TPM),同时计算输入和输出。输入 token 在请求时已知;输出 token 必须事后估算或追踪。实践中的做法是:在准入时统计输入 token 并对每个租户每个时间窗口强制执行 token 预算,然后在生成过程中将实际输出 token 计入该预算。
三种算法主导了生产环境的实现:
令牌桶(Token bucket) 以稳定速率填充,并允许突发到桶的容量上限。这很好地模拟了实际提供商的行为——大多数 LLM API 以固定 TPM 速率补充,并允许短期突发。令牌桶是大多数应用的正确默认选择,因为它在保障平均速率公平性的同时支持突发容忍型工作负载。
滑动窗口(Sliding window) 根据滚动时间间隔评估请求。它防止了固定窗口允许的边界利用(在一个窗口末尾和下一个窗口开头各发送最大请求量),但在分布式系统中实现更复杂。
优先级队列(Priority queuing) 不通过丢弃请求来限速——而是在系统过载时通过排队低优先级请求来优雅降级。交互式用户请求获得高优先级;后台批处理任务在有容量时处理。对于宁愿增加延迟也不想返回错误的应用,这是正确答案。
基于 token 的速率限制开销可以忽略不计——约 4ms——与模型生成时间相比微不足道。没有理由跳过它。
一个常被忽视的关键点:速率限制必须在 LLM 调用派发之前执行,而非之后。事后检查 token 预算意味着失控的租户已经消耗了你无法追回的资源。执行点属于你的 API 网关或推理代理,而非应用代码。
租户隔离的三个层次
多租户 LLM 基础设施需要在三个独立层次上实现隔离:推理层、检索层和上下文层。大多数团队实现了其中一两个,然后以惨痛的方式发现了第三个。
推理层隔离
对于大多数应用,共享模型实例加上每租户速率限制和预算追踪就足够了。风险不在于租户共享模型权重——他们始终如此——而在于某个租户的资源消耗拖慢了其他人的延迟。速率限制可以处理这个问题。
对于受监管行业或高安全需求,每租户独立的模型实例提供硬隔离。这代价高昂:每个独立实例意味着一块或多块 GPU 专属于一个租户,无论其是否活跃使用。这种经济模型仅对有强合规要求的高价值企业客户成立。
中间方案是命名空间级隔离:共享 GPU 资源加上调度器强制公平性。SGLang 和 vLLM 等现代服务系统支持连续批处理,跨同一 GPU 资源交错处理不同请求的 token 生成。通过适当的准入控制和每租户 token 预算,这在无需专用硬件的情况下实现了合理的公平性。SGLang 的 RadixAttention 内存管理器对于多轮工作负载比基准 vLLM 提供约 29% 的更高吞吐量——服务层的架构选择显著影响多租户效率。
检索层隔离(RAG)
这是大多数实现存在漏洞的地方。当租户共享向量索引时,检索隔离不仅仅是添加一个 tenant_id 过滤器,还需要在查询时、在结果到达生成层之前强制执行该过滤器。
关键错误是检索后过滤:先从整个索引检索,再丢弃属于其他租户的结果。这是数据泄漏风险——在过滤器运行之前,来自一个租户文档的文本块出现在另一个租户的检索上下文中。更重要的是,这很低效:你为立即丢弃的内容支付了检索和嵌入的费用。
三种模式在不同规模下处理 RAG 隔离:
每租户独立集合 提供最干净的隔离。每个租户拥有自己的向量集合。从设计上就不可能发生跨租户查询。权衡在于运营开销:在每次租户入驻时创建新集合,分别管理索引大小,即使是文档量少的租户也需要支付固定成本。
共享索引中的命名空间(Pinecone 的方式)或分区集合(Qdrant 的分层多租户)提供了中间方案。租户在索引内相互隔离,但共享底层存储和计算。这能高效处理常见情况,但不提供硬隔离保证。
余下内容仅对会员开放。
会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
- 完整文章,包含未公开存档的部分
- 可落地的工作框架,附带权衡与决策依据
- 新文章抢先看,先于公开发布
随时取消 · 一次订阅,畅读全部
