loading

Loading

探索与发现

首页 AI 开发实战

推理服务多租户配额:抢占落地时的取舍

字数: (2408)
阅读: (4)
0
摘要:从核算口径到抢占的停止条件,拆解多租户推理服务里配额该怎么落,哪些抢占行为可控、哪些会让客户账单先出问题。

多租户推理集群里,配额能不能生效,最后都落到同一个问题上:当一个租户的请求已经排进队列,另一个租户突然要资源,谁的活被干掉、损失多少、什么时候再干。这件事做强了,用户体验稳定但 GPU 空转;做弱了,利用率上去但大客户月底对账单会发现自己在给别人的长尾请求买单。工程上通常是在 Kubernetes 这一层用 Queue 和 ElasticQuota 把预算约束住,再把真正的抢占语义下沉到推理服务的排队器里,因为 GPU 显存的抢占代价和 CPU 完全不是一个量级。

配额分成两层,中间那层最容易失控

线上常见的做法是配额分两处写:Kubernetes 侧用 ResourceQuota 或 Volcano 的 Queue、PodGroup 控制命名空间能拿多少卡,推理服务内部再用自己的令牌桶控制 QPS、并发数和 Token 预算。两层之间没有强一致性。案例里并不少见:某个租户 K8s 配额还剩一百多张卡,可是业务侧因为反馈回路的延迟,早就把并发数打满,从推理服务的视角看,这个租户一直在超卖的边缘跑。

较稳的一套办法是把对外暴露的“物理卡数”去掉,直接定义成租户的 Token 配额。一个租户一个月能用多少 Token,这个上限落在推理队列上,Kubernetes 层的配额只作为总量护栏。好处是账号和用户能看懂,账单和配额也对得上;坏处是这套换算一旦写上,就得用若干次压测把 Token 与 GPU 卡时之间的偏差摸清,不然低端卡的租户会觉得自己被占了便宜。对不追求精细的团队,有更简单的办法:以租户口径的并发份额给推理队列分红,K8s 数量折成一份上限,先不打算跑满。

抢占的停止条件比抢占顺序难

多租户抢占真正难的,不在排序上,在什么时候停手。资料里对抢占有两条对比值得注意:在线推理的请求对延迟敏感,且 KV Cache 没法像训练 Checkpoint 那样事后恢复。GPU 一旦被抢,正在跑的这组 decode 循环就一并作废,接受和拒绝对应的是同一个用户请求的两种命运。放进队列的全都被打断,用户拿到超时失败。

GPU 集群上用得较多的做法有两种。一种是在推理实例和队列之间共用准入,在分配 GPU 卡时,把“这批请求对应的整个 KV 缓存块”视作待驱逐资源。驱逐前先把实例上的常规会话在外部前端进入承接状态,并回传“已缓存的 token 前缀”断点标记,代价是失败率按此处的卡数组合放大。基础服务里用计算量很少的请求测试确认到效果不太一样:这种方式的回放比切断请求简单,但恢复时会重复做 prefill,对 Prefill 时间长的模型等于花了两次钱。

另一种是可抢占级别的强隔离:用独立推理实例承接低优先级租户,放到独立机位上,不足或空闲从它这里腾挪。此处的限制来自集群规模:低优先级集群的卡数无法专门批出,即便批出,训练用的抢占试验就需要额外拿出一批卡来做这些调度测试,配额调整本身没那么多集群可以试。

给低优请求一个明确的去路

最容易出状况的是低优先级租户本来没该被打断的请求,具体故障更像是“租户在等用户付卡,用户买了卡进去,秒回已扩容,又被告知重排”。若不去把抢占直接和量价绑定,而是先在流控制上标出低优先作业进程在调度上的分组,在网关附近跑上一个独立队列:租户可以选配额模式是“被抢时直接转去停止”还是“抢先可接受的超时上,把转发比例摊薄”。后者目前可选的退避点是“接受方上限”或“因实例延迟”,没有通用阈值。

我们手上的做法是把退避切成尺寸序列:靠前次发出去比到点,保住这条降级路径时最先唤醒的几个会话;若本轮小请求前几次一直被预执行推迟,就直接换走。这个过程不影响重启次数,只是分给当前总量。它在租户从固定副本推来的那几条线上有效,而这些恰是抢占优先会冲的最前面时最常见的情形。对稳定流量型的用户,差别反而是量价本身。

预留必须算进账单

抢占要收窄先得有一个假定:每个租户要为它没用的预留位付钱,即使实际运行只跑了一会儿。许多推理平台早期做弹性扩容,不留预留,这些与业务无关的调头就省了;但只要整卡没法回收,同卡上起的实例在同一批用户之间内挤占,每个新来者能拿到的响应时段就不与请求量成比例。

资料里给出的做法是把各租户的配额逐步落到“预热 + 空间预热”上,每月限额里各拿小整来挑预留位,一开始多留给已经在跑的池子,免得过一张新账单就让出所有卡。要拿更多可抢占的余量,首先要接受抢的那一侧并不是只用单卡上线,且长期高优业务不愿被抬进抢占级队列,量基本压在会干扰同池来留。

更多是把每一条抢占记录都显示在上层账单上,靠月度分摊,让每个人看清自己拿到的量多不多、每一分被挤掉的容量是否正落到另一个满载或闲置的物理集群里。这里别把固定配额死贴着按月结算的包干价,否则很难比出谁该被赶走;按分或卡的时长核算更适合让企业侧和容天卡数的占比在同一个地方看清明细。工程师更该统计每个租户因抢占被重排多少 GPU 卡时。

拒钱比杀活更可取

有时需要的只是阻止新副本进入某个分区,而不是拦停现有新副本之外的全部作业。可访问性和性能双方面的多租户隔离中,最实用的工程边界线应是:不为超额度入的即时应答留缓冲;靠外部请求侧在限流层打出明确的拒绝“四零几”,让用户沿重试策略自己往返回退一步。很多事例说明:新请求不预加热,也至少要给租户按每天分秒级别的补退实例量。相对抢占而言,不把接入池的计划提前向下游通告,预占额挂倒很多回,发现批量退路的进程要一次次的确认。

一个还在变化的方向就是排队加计费把整个流绑在一起,但在项目预算里,这一整块的开发量按着抢回来的机器算出来的增速放在中间,因为 GPU 卡本身变硬之后,隔离方案只在能用主分配规格的成本上压缩才会变得可接受。推理集群的默认值不该是做得比当初设计的多完美,而是对抢占的最前置答案(准入不足就先出可见告警),能让被抢占的卡量算到核算数据里。

转载请注明出处: 皮哈皮阿

本文的链接地址: https://blog.phpat.com/ai-dev/648.html

手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

您可能对以下文章感兴趣
1 / 1
预览图