跳到主要内容

多租户 LLM 问题:规模化部署中的嘈杂邻居、隔离与公平性

· 阅读需 13 分钟
Tian Pan
Software Engineer

你的 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 的分层多租户)提供了中间方案。租户在索引内相互隔离,但共享底层存储和计算。这能高效处理常见情况,但不提供硬隔离保证。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates