尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

大模型推理分布式调度:缓存感知路由与全局准入控制

发布时间:2026/9/24 21:08:22

资讯中心
01
ARTICLE

大模型推理分布式调度:缓存感知路由与全局准入控制

大模型推理分布式调度:缓存感知路由与全局准入控制
做过三年多推理系统我最大的体会是单机性能再猛也架不住把流量胡乱分到一堆机器上。之前我们压测多卡集群总以为轮询转发就算负载均衡结果第一台GPU已经干到97%后面几台还在百分之三四十晃悠线上P99直接拉胯。后来我把研究重心从“怎么把GPU算得更快”挪到“怎么把请求派得更聪明”整个集群的吞吐才算真正上去。这篇是本系列的第5篇聚焦分布式场景下的大模型推理调度核心就两个词缓存感知路由、全局准入控制。这篇文章适合正在搭推理服务集群、或者已经发现“单机没问题、多机全是问题”的团队。里面绝大部分思路不是paper里那种理想模型而是我们在生产环境真刀真枪调过的方案。我把设计逻辑、实现细节、踩坑过程都摊开来讲你照着能落地的程度写的。1. 分布式推理调度到底在解决什么问题1.1 先搞清楚单机调度和分布式调度差的不只是层数很多人拿到推理服务第一时间想的是优化算子、搞continuous batching这些当然重要但它们属于单机调度范畴一块GPU上同时跑多少个请求、KV Cache怎么分配、decode阶段怎么组batch都是在一个节点内解决的。分布式调度不一样它多了一整层“请求该去哪个节点”的决策而这个决策会直接决定单机调度有没有发挥空间。你可以这么理解单机调度是“食堂窗口怎么排队炒菜”分布式调度是“顾客应该被引导到哪个食堂窗口”。引导错了就算所有窗口的厨师都是顶级水平照样有的窗口排长队、有的窗口闲着。所以分布式推理调度本质上是一个两级调度问题。第一级是节点间的路由决策第二级才是节点内的batch调度。这两个层级不是割裂的路由决策需要考虑节点内部的显存状态、排队长度、缓存命中情况节点内调度也要预留出处理路由决策的接口。很多团队直接拿普通的负载均衡器来做第一级完全不懂节点内部状态结果就是上面那个场景负载均衡器觉得大家都在干活实际上活儿全堆在一个节点上了。1.2 调度目标拆解吞吐、延迟、成本与稳定性怎么平衡推理调度优化的目标不像“越低越好”这么简单至少四类指标要一起看吞吐每秒完成多少请求、产出多少token、延迟TTFT首token时延、TPOT单token时延、稳定性P99、SLO达标率、成本单位token的GPU开销。这四个目标天然有冲突。最典型的就是为了提升吞吐和降低成本你会希望batch尽量大、显存尽量占满但batch太大又会让每个请求的等待时间变长TTFT飙升。为了满足P99 SLO你甚至得故意让GPU空转一些留出处理突发流量的水位。这就牵出了分布式推理调度最核心的取舍缓存亲和性和负载均衡之间的冲突。大模型推理有很强的前缀复用特征一批请求如果共享系统提示词或者文档前缀放到同一个节点上就能复用已经算好的KV Cache大幅跳过prefill计算。从缓存角度出发最好把所有共享前缀的请求都打到同一个节点但从负载角度出发这样又会造出一个热点其他节点闲着。调度器必须在“缓存命中收益”和“节点负载均衡损失”之间做一个量化权衡。后面讲的缓存感知路由本质上就是在做这个权衡决策。2. 缓存感知路由让请求尽量命中该命中的节点2.1 推理场景里缓存的是什么先讲清楚一个容易被忽略的点大模型推理里的缓存不是HTTP缓存那种“响应结果直接复用”而是KV Cache。模型在生成每个token时都要计算Key和Value矩阵存下来之后后续token生成只需要读这些矩阵不用重新算一遍历史token的注意力。KV Cache大小跟序列长度成正比一个跑着长上下文的请求能吃掉好几GB显存一旦处理完就得释放后面再有新请求还得重新计算。但KV Cache里有一部分是可复用的相同前缀的token序列计算出来的Key、Value是完全一样的。比如很多应用会在每个请求前面拼一大段system prompt或者用户反复编辑同一个文档后重发这些场景里前缀部分的计算结果完全可以复用到新请求上。系统把这些按块缓存起来就是prefix cache也有人叫prompt cache。放到分布式环境下模型权重在每个节点都有一份但KV Cache是分散在各节点显存里的独立资源。A节点的缓存是A节点独有的B节点没有。所以路由策略就有了新的优化空间如果请求的前缀hash能在某个节点的缓存目录里命中就把请求送到那个节点prefill的耗时能省掉一大半。拿生活打比方更直观你在好几个窗口都能点同一道菜但只有某一个窗口的厨师把你这锅汤底已经熬好了你当然优先去那个窗口。缓存感知路由干的就是这件事。2.2 路由决策要综合哪些维度缓存感知路由不是简单“看谁有缓存就送谁过去”实际决策要综合很多维度每个维度还得有权重。我们生产里至少看四类信息缓存命中收益当前请求前缀哈希在目标节点上的命中长度、命中字节数。命中越多跳过prefill的收益越大。节点负载GPU利用率、正在处理的请求数、排队长度、KV Cache剩余可用块数。节点快爆了缓存收益再高也不能去。节点健康状态是否还活着、是否处于熔断、最近有没有超时波动。这些信息通常由节点代理上报。请求自身约束比如请求要求的SLO等级、模型版本、部署区域。有些请求只能去特定部署单元。把这些维度凑成一个打分函数然后调度器给每个候选节点算分取最高分。我在项目里常用的一种带老化因子的打分方式是这样的def score(node, req): cache_gain node.prefix_hit_bytes(req.prefix_hash) / req.prompt_bytes load_factor node.kv_cache_used_ratio node.queue_len * 0.05 health 0.0 if node.healthy else 1.0 return ( 0.5 * cache_gain - 0.3 * load_factor - 0.1 * health 0.1 * node.recent_slo_satisfaction )权重需要根据线上流量动态调没有固定答案。我们曾经为了刷缓存命中率把cache_gain权重调到0.7结果一个热门前缀把单台节点打爆其他节点全部闲置。后来加了负载惩罚的动态调整逻辑命中率收益超过一定程度就开始衰减才解决这个问题。2.3 路由信息如何收集和维护路由要感知缓存前提是调度器能快速知道每个节点的缓存目录长什么样。大模型模型的prefix cache是按块block组织的每个块对应一段token序列的KV值会有一个哈希标识。节点代理需要把“节点里缓存了哪些前缀块、这些块分别占了多少显存”整理成一个可检索的索引定期上报给调度器。这里有个实用技巧不要上报完整的前缀树那个数据量大到没法实时同步。我们只上报缓存块的哈希列表和块的引用计数也就是“这个块当前被几个活跃请求持有、在缓存队列里的优先级是多少”。调度器收到之后在内存里维护一个前缀哈希到节点集合的倒排索引查一个请求的前缀直接返回命中节点列表。上报频率也是个容易踩的坑。太快了调度器被消息刷爆节点本身也白白浪费CPU太慢了调度器拿到的是过期快照把请求路由到缓存已经失效的节点。我们最后是“心跳增量更新”配合常规状态每500毫秒心跳一次缓存块变化超过阈值立即触发增量上报既保证了实时性又把流量控制在可接受范围。2.4 缓存命中不了时的兜底策略不管索引维护得多及时总有命中不了的时候。比如缓存块被淘汰了、节点因为过载放弃了某个前缀、或者请求前缀太长导致缓存目录里没有足够长的匹配块。这时候路由要有一个优雅降级的逻辑不能把缓存命中当成硬约束。我们用的策略是先按打分函数选出得分最高的节点再判断这个节点是否健康、是否有足够KV Cache余量。如果候选节点过载就不再强求缓存亲和性直接选一个负载最低的节点去执行。虽然会造成一次额外的prefill计算但比挤爆一个节点再把请求杀掉要好得多。另一种特殊情况是某个前缀非常热多个节点都在缓存它。这时路由反而不能只盯一个节点因为热点流量会把单个节点的KV Cache挤爆。建议在缓存索引里给每个前缀维护多个命中节点路由时按负载比例分发甚至可以主动把热门prefix同时预热到多台节点上让流量均衡地落在几台机器上同时每个节点都有较高命中率。3. 全局准入控制过载时才见真章的保护机制3.1 单机限流在分布式场景下为什么不够很多团队的兜底策略是给每个节点配“最大并发数”到顶就返回429。单机限流在单机场景下没有问题但在分布式场景下会暴露一个致命缺陷缺少全局视图导致无法在整体容量尚有余量时做出正确的准入决策。举例说明我们有个5节点的集群每个节点单机限流是200路并发。某一时刻流量飚到800路并发节点分配最理想的情况是每台160离限流还有余量。但由于路由算法或者外部流量倾斜可能某两台节点已经被打到300另外三台只有70。这时候按单机限流处理那两台过载节点开始大量拒绝请求但全局集群其实还有210路的余量没有被利用。用户感受到的就是“系统故障了”哪怕集群大部分节点还在闲置。更麻烦的是优先级问题。生产里往往同时跑着线上高优先级请求和离线分析任务。如果只做单机限流离线任务可能先把某台节点的限额占满等高优先级请求轮到这台节点时直接被限流拒绝整个系统的SLO被低优先级任务拖垮。全局准入控制才能解决这种跨节点优先级调度问题。3.2 全局准入控制器的设计思路与关键参数全局准入控制器的位置一般放在路由网关这一层先于路由决策触发。它的核心职责是回答一个问题以当前集群的全局状态这个请求能不能进、进了之后应该排队还是立刻拒绝。判定请求能不能进不能只看请求数得看资源量。大模型推理最紧缺的资源是显存里的KV Cache空间块其次是并发执行线程数。所以我们的全局准入控制做了两层资源预算第一层是全局并发请求数第二层是整个集群可用KV Cache块的预估占用。每个请求进来时会先估算它可能消耗的KV Cache块数估算公式是“prompt长度 预估生成长度”除以每个块能容纳的token数然后乘以一个安全系数。这里要说一个关键设计全局准入控制应该留出缓冲水位而不是等到资源用尽才拒绝。生产里我们设置两个阈值黄色水位是80%到这个水位开始拒绝低优先级请求、降低离线任务额度红色水位是90%到这个水位所有新请求默认排队只有高优先级请求能插队。缓冲水位的作用是应对资源估算误差和突发流量因为请求实际消耗的KV Cache往往比预估高。全局准入的同步方式可以采用“预留释放”的模式。调度器接到请求后先在全局资源账本上预留资源如果成功再下发到具体节点请求结束或排队超时时释放预占资源。这里务必要考虑预留了资源但节点调度失败的情况需要引入一个短超时和自动补偿释放机制否则预留资源泄漏会让准入控制器逐步锁死整个集群。3.3 拒绝、排队与重试风暴防护准入控制判定请求不能立即执行时有两种选择返回一个明确的拒绝信号或者让请求进入有界队列等待。直接拒绝最简单但会把压力传导给用户客户端往往会立即重试反而把系统打得更惨。全部排队也不现实因为队列本身也要消耗内存还可能让请求在队列里等到超时用户体验更差。我们的做法是做一个分层策略高优先级请求允许进入有界队列队列长度按“预期可用资源”动态调整低优先级请求超过全局水位直接拒绝。有界队列的长度很关键没有一个固定值我们是用“队列中请求的平均预估执行时间”乘以一个系数来推算保证一个请求在队列里能被清走而不是排到天荒地老。重试风暴防护是准入控制最容易忽略的一环。拒绝请求时响应里一定要带上Retry-After之类的退避提示网关侧还需要对同一个客户端来源做重试检测一旦发现短时间多次重试直接把该源头标记为惩罚状态优先拒绝。我们在实际生产里见过最严重的场景某个客户端拿到429后立即重试同一批请求被放大十倍打回来直接冲垮本来还有余量的集群。4. 调度、路由和准入控制如何组合成一套系统4.1 系统架构网关、调度器、节点代理各自干什么前面讲的缓存感知路由和全局准入控制不是两个独立系统它们必须拧成一个整体。我们落地后的组件划分大致是这样的模块核心职责关键状态主要接口请求网关接收流量、识别请求元信息、接入准入控制、发起路由客户端来源、请求优先级、超时策略HTTP/gRPC入口全局调度器维护全局状态、打分路由、执行准入决策节点负载表、前缀缓存索引、全局资源账本上报接口、准入接口、路由接口节点代理本地排队、执行推理、上报状态、执行本地调度本地KV Cache用量、队列长度、缓存块索引推理执行RPC、心跳上报状态存储持久化节点状态给调度器做高可用选主节点注册信息、调度器主备状态选主接口、状态同步有人会问调度器为什么不能把状态全放内存非要配一个状态存储因为在多副本部署下调度器如果只有单点挂了整个集群就瘫了如果多副本各自维护状态又会不一致。我们采用的方式是调度器多副本抢主只有一个主节点在做路由决策状态存储只负责保存节点注册信息和心跳租约。真正的实时负载和缓存索引在主调度器内存里从调度器通过订阅的方式保持热备。4.2 一个请求走过的完整调度链路一个请求从进来到出结果在分布式调度系统里走的是这样一条链路第一步请求到网关。网关先解析请求里的元信息模型名、prompt内容或prompt哈希、请求优先级、SLO等级。这些信息在后续两步都要用。第二步准入控制。网关调用调度器的准入接口调度器根据全局资源账本判断能不能接能接先从账本里预留资源不能接直接返回429或者进队列。这里要注意准入判断必须发生在路由打分之前因为如果目标节点都没有资源了路由选了也没用。第三步缓存感知路由。调度器拿请求的prompt哈希去查前缀缓存索引找到可能命中的节点候选集再结合负载、健康度打分选出最终节点。这个步骤要快我们要求整个准入加路由的决策延迟不超过3毫秒否则对TTFT的拖累就太大了。第四步节点代理接收请求并进入本地调度。节点把请求放进自己的batch队列由单机调度器决定何时执行、跟哪些请求合成一个batch。如果本地KV Cache不足节点代理还可以向调度器发起一次“重路由请求”由调度器重新选一个节点避免把请求卡死在过载节点。第五步推理完成结果返回给网关同时节点代理释放本地KV Cache并向调度器上报最新的资源和缓存变化。调度器在资源账本里释放该请求预占的资源整个闭环完成。5. 实操落地从0到1的关键步骤与排查实录5.1 起步实现先做减法再做加法我见过太多团队一上来就照着字节或者某大厂的架构图纸去搭控制系统结果做了一半发现根本维护不起。如果你是从零开始我强烈建议先做减法先不搞全局准入先做缓存感知路由先不搞复杂的编排先在一个中心调度器里把逻辑跑通。第一步做一个节点代理的心跳上报。上报内容先不用详尽至少有节点ID、GPU利用率、KV Cache已用比例、正在处理请求数、前缀缓存哈希列表。这一步已经能解决很多实际问题比如“负载均衡器把请求打到一个满的节点上”。第二步在网关或调度器里实现一个简单的缓存感知路由。不需要自己造分布式存储用Redis或者etcd存前缀哈希和节点的映射就够了。路由频率高可以考虑在调度器本地维护一份缓存表订阅Redis的更新事件来同步。第三步加入资源预留和全局并发限制。先不要做token级的精细预算直接限制全局并发数为“节点数乘以单节点最大并发倍数”就行。跑一段时间看有没有因为并发超卖导致的排队超时再逐步精细化。第四步再做token级预估。这一步需要把请求prompt长度和预估生成长度上报给调度器调度器维护一个全局KV Cache块账本。这一步要小心估算偏差建议代码里对每个请求预占的块数加10%的保险系数。5.2 压测与调优关注哪几个指标压测分布式推理调度系统不能只看整体QPS高不高要分层看指标。我们内部跑压测至少看这五类缓存命中率精确到“每个前缀哈希的命中比例”这个指标直接反映路由策略有没有帮上忙。TTFT和TPOT的P50、P99用来判断准入和路由的决策延迟有没有拖累请求。节点间负载标准差标准差距越大说明路由越不均匀热点问题越严重。全局准入拒绝率太高说明容量预估或者缓冲水位设得有问题太低说明准入机制没有在真正工作。SLO满足率最终审判指标前面所有指标都是为了它。压测场景要覆盖两种情况共享前缀流量为主比如客服系统所有用户都带同一套系统提示词和随机长尾流量为主比如各种用户自由输入。缓存感知路由对这两种场景的收益差距很大你需要在压测里搞清楚自己的业务属于哪一类。调优参数的时候优先级应该是先调路由的负载均衡能力再调缓存命中权重最后调准入水位。很多人上来就猛调缓存命中率结果热点问题爆发前面调优全部白费。5.3 生产环境典型问题速查表最后整理一份我在生产里真实踩过、或者帮别人排查过的问题清单。问题现象可能原因排查方法建议修复某个节点持续打满其他节点闲置缓存感知权重过高热点前缀全部路由到同一节点看按前缀哈希拆分的节点流量分布调低缓存权重对热门前缀做跨节点预热全局资源明明充足却大批量返回429准入控制预留资源没有释放存在泄漏比较全局账本预留量和实际执行量加预留超时补偿释放机制缓存命中率一直上不去上报频率太低调度器拿到的是过期缓存索引对比调度器索引和节点实际缓存块摘要增加增量更新逻辑请求在各节点之间反复跳转路由打分函数对负载抖动太敏感看节点负载数据是否有毛刺打分函数加滑动窗口或平滑因子客户端报错重试后系统雪崩拒绝后没有退避机制看网关层有没有重试次数放大响应带Retry-After网关做重试熔断调度器挂了之后整个集群不再接收新请求准入和路由强依赖单点主调度器检查调度器是否有热备改造成主备自动切换状态存etcd/Redis这些问题的根因大多不是某一个模块特别复杂而是模块之间状态不一致。所以我一直强调分布式调度系统真正难的不是写一个牛逼的打分函数而是把状态同步、超时处理、舆情降级这些脏活累活做扎实。如果再给一个建议我会说上分布式调度之前先把可观测性做起来。我们很多问题排查半小时一半时间是在查日志、看监控后来把每个请求的最终路由节点、命中缓存前后字节数、准入拒绝原因全部打点出来排障效率翻了几倍。缓存感知路由和全局准入控制不是一锤子买卖是靠不断看数据才能调到最优的活。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。