周四下午两点一刻,你的团队两周前上线的内部助手突然被全公司同时使用。支持频道里同一个抱怨以六种语气涌来:是挂了吗?我这边一直在转圈。早上还好好的。有人贴了一张没有配文的加载截图,你怀疑他挺享受这个时刻。

你打开仪表盘。节点就绪,Pod 在跑,CPU 只有 20%。没有重启,没有 CrashLoopBackOff,没有告警触发。按 Kubernetes 给出的每一个信号,系统是健康的。

打开网易新闻 查看精彩图片

但它不健康。有人已经等了 11 秒,还没等到答案的第一个字。他正准备回到老办法去干活,而且不会回来了。这篇文章讲的就是这种故障——不是宕机,是那种安静的故障:一切技术上都在运行,产品却已经不可用。

你的第一反应是错的

那一刻的本能是怀疑模型。版本不对、量化有问题、上下文太长,或者有人改了系统提示词。几乎从来不是模型的问题。

把一个请求从头到尾走一遍,你会看到四个阶段:它被路由到一个副本;它在队列里等待;模型读取提示词;模型流式输出答案。只有后两个阶段涉及你付费让模型做的事。前两个是排队和路由,也就是基础设施。

当人们说自己的模型很慢,模型通常是好的。等待发生在别的地方。

你不是唯一一个

在开始排查之前值得知道:这是这个领域最常见的抱怨,不是你不走运的配置。一项针对 200 名在生产环境运行 AI 的从业者的调研发现,接近一半、也就是 49.5% 的人把峰值负载下的延迟列为他们最难解决的扩展问题。不是准确率,不是幻觉,不是每 token 成本。是延迟,而且恰好发生在人们想用这个东西的时刻。

同一份研究里还有两个数字值得放在一起看:59.5% 的人认为把推理跑得离用户或决策点更近是关键的或非常重要的;45.5% 仍然只从单一云区域提供服务。人们知道距离重要,却没能付诸行动,这说明了搭建多区域 GPU 容量要付出什么代价。

同一份研究还提到,有组织把 250 毫秒以内的响应时间和 99.9% 的可用性并列写进要求。仔细读这句话,因为按字面理解它是不可能的。没有任何有意义的 LLM 响应能在四分之一秒内完成。它指的必然是首 token 时间,也就是答案的第一个字出现之前要等多久——而这本来就是你该拿来自我要求的指标。一旦 token 以可读的速度流动起来,人们就不再计数了。失去他们的是第一个 token 出现之前的那段沉默。

部署时没人告诉你的那件事

普通 Web 请求短、小,成本大致和上一个请求相当。Kubernetes 的调度假设如此,Service 的负载均衡假设如此,Horizontal Pod Autoscaler 假设如此,你的 ingress 控制器默认超时也假设如此。没人把这个假设写下来,因为十五年来它就是事实。

一个 LLM 请求在三个地方打破了它。它分两个阶段运行,两阶段的特征完全不同。预填充阶段,模型一次性读完整个提示词,受算力约束、突发性强,它决定了用户盯着空白要盯多久。然后是解码阶段,一次一个 token,每个 token 都需要此前所有 token 累积下来的状态。这个状态就是 KV 缓存,它和权重一起住在 GPU 显存里,并随着答案变长而增长。

所以请求不短,它们可以跑上一分钟。成本也不一样,一个粘贴了文档的提示词,成本可以是一句话提示词的 50 倍。真正稀缺的资源是 GPU 显存,而它不出现在你继承来的任何一块仪表盘上。这就是为什么你的监控说一切正常——它在测量错误的机器。

那 11 秒去了哪里

跟着请求走完四个阶段,故障模式会依次浮现。从业者最常提到的有六种,它们和这条路径对得很整齐。

第一阶段是路由:你的负载均衡器在猜。请求成本一旦分化,轮询就不再公平。三个重提示词落到同一个 Pod 上,而它旁边的 Pod 在处理一句话请求。被压满的 Pod 队列增长,尾部延迟攀升,而整个集群的平均值看起来依然完全合理——这就是为什么今天之前没人注意到。

长连接让情况更糟。用 HTTP/2 或 keepalive 时,客户端打开一条连接,把所有东西都发下去,而 Kubernetes Service 是按连接而不是按请求做均衡的。所有流量被钉在同一个后端上,并且一直留在那里。

还有一种大多数团队从未考虑过的成本。如果一个副本的 KV 缓存里已经存有这个提示词的前缀,路由到它就能省下真实的预填充工作。由于大多数生产提示词共享一段很长的系统前言,这不是边缘情况,而是你大部分流量。轮询每一次都在随机地把这个好处扔掉。

第二阶段是队列:没有任何东西会来帮忙。第三阶段是预填充:GPU 就在那里,却毫无用处。第四阶段是解码:你的入口正在把人切断。而在四个阶段之下还有一层:突发流量,以及没有人愿意在问题上署名。