每个基于并发的自动伸缩器都运行在一个关于并发含义的模型之上。默认模型假设处理大量并发请求的 Pod 正处于高负载状态,而处理少量请求的 Pod 则处于空闲状态。当并发请求可以作为 CPU 压力的代理指标时,这是一个合理的模型,因为每个请求都需要 CPU 来提供服务,并且只占用很短时间的资源。信号与底层约束高度相关。
流式处理(Streaming)打破了这种相关性。一个 Pod 可以持有 100 个并发连接,但 CPU 使用率仅为个位数,因为每个连接的工作主要是等待上游供应商的字节流,然后进行转发。基于并发的自动伸缩器读取这个数字,判定 Pod 过载,并部署更多副本。新副本启动后,接管了连接池中的份额,CPU 使用率同样保持在个位数。仪表盘现在显示整个集群的 CPU 运行率只有 5%,而自动伸缩器仍在继续扩容,因为它识别到的唯一信号表明并发量很高。
修复方法需要让自动伸缩信号与实际约束相匹配。对于流式网关(Streaming Gateway),约束通常是打开的连接数——不是 CPU,也不是内存,而是 Pod 在其连接表或文件描述符数量饱和之前可以持有的正在进行的流的数量。自动伸缩器应该直接根据该数值进行缩放,利用率定义为连接上限的比例,而不是每个 CPU 的并发量。队列深度指标或待处理请求时间指标是领先指标;CPU 则是一个滞后指标,流式处理已经有效地将其与负载解耦。
确立服务成本基础的容量规划对话是围绕每秒请求数展开的。成本模型认为:在峰值时我们每秒处理 N 个请求,每个请求的基础设施成本为 X 美分,因此我们的月度账单是可预测的。当每个请求都是计算资源的瞬时消费者时,这个模型是对的。但现在它错了,因为流式请求消耗的资源不是 CPU 秒,而是连接秒(Connection-seconds)——连接秒的价格取决于连接持有的时间,而不是单位时间内到达的连接数量。
随之而来的架构认知是:流式处理使得模型的行为——它的 Token 速率、平均响应长度、推理深度——成为基础设施账单的直接输入。决定启用一个推理时间更长、能力更强的模型的产研决策,同时也是一个基础设施成本决策,而这两个决策是由不同团队做出的。当 AI 团队选择模型而平台团队支付持有时间费用时,成本分摊缺口就出现了,而且两者之间的联系在任何一个团队的仪表盘上都不可见。一个根据预期持有时间(源自实际流量,并在模型更改时刷新)为每个请求定价的容量模型,才能弥补这一缺口。否则,平台团队将永远对上游模型选择带来的基础设施后果视而不见。
教训隐藏在这些故障模式之下。响应离开系统的协议层级变更,是与 API 网关下游所有环节的一次契约变更,而这个契约必须明确地重新协商。流式响应在传输线路上并非免费。总有人要为持有时间付费,而那些没有预算好由谁付费的团队,最终仍会收到账单,只是这笔账单会以难以理解的形式,散落在各个与发布毫无关联的基础架构层面上。