大模型服务从来不是一台机器扛所有请求,负载均衡就是那个分单的人:它看着一堆实例,决定每个请求去哪一台。
请求为什么会挤到一台机器上
最朴素的轮询看着公平,却不管机器状态:一台正在跑长生成,另一台刚空闲,新请求还是按顺序来,空闲的等活、忙的冒烟。进来的是请求流,发生的是无差别派发,出去的是有的过劳、有的闲。
按连接数分流稍好,但大模型请求的耗时差得远:一个长文档问答能占几十秒,一次短提问几百毫秒。用连接数当标尺,照样分不均。
还有一类不均来自请求本身:长文档问答占用久,短提问秒回,混在一起时任何简单策略都会失真,必须按耗时特征分别对待。更隐蔽的是慢启动:新加入的实例还没预热,就被派了重活,响应慢又拉低整体水位,形成恶性循环。
分不均的代价会传导给用户:同样点一下发送,有人秒回,有人干等半分钟,体感上就是产品时快时慢。分流的目标就是把这种差距压到可接受范围,让体验不取决于自己撞上哪台机器。
| 分流做法 | 标尺 | 短板 |
|---|---|---|
| 轮询 | 按顺序轮流派发 | 不管机器状态,忙的冒烟、闲的等活 |
| 按连接数 | 连接数多少 | 大模型请求耗时差得远,照样分不均 |
| 按负载水位 | 在途请求数、队列长度、显存余量 | 与缓存亲和性冲突时要取舍 |
分流决策的三个输入
第一个输入是健康检查。实例要定期报状态,掉线的先摘出去,恢复后再放回来。进来的是心跳,发生的是存活判定,出去的是可用实例清单。
第二个输入是负载水位。队列长度、在途请求数、显存余量都可以当标尺,谁水位低往谁派。进来的是实时指标,发生的是加权比较,出去的是目标实例。
负载水位的指标要选能反映排队长短的:在途请求数比连接数更准,队列长度比吞吐更直接,组合起来看更稳。
第三个输入是亲和性。同一用户的后续对话尽量落到有它缓存的实例上,否则 KV 缓存要重建。进来的是会话标识,发生的是粘性路由,出去的是老实例优先的决策。
三个输入常有冲突:负载最低的实例偏偏没有用户缓存,这时候要在「均衡」和「粘性」之间选一个容忍度,通常优先保粘性,因为重建缓存的代价更高。
权重与健康检查怎么配合
不同机器算力不同,权重就是给它们不同的派单比例;健康检查负责把不可用的权重临时清零。两者一个管倾向、一个管底线。
健康检查的探针本身也要轻:查得太勤浪费带宽,查得太松漏判故障,常见做法是连续多次失败才摘除,避免一次网络抖动误杀。
权重也不是一成不变:扩容后新实例权重从小往大抬,避免一上线就被洪峰打懵。你在通义千问、文心一言里遇到高峰时段,服务不抖,背后常是多实例加分流策略在兜底;新实例也是先小流量试水,再慢慢加到标准权重。它不改变单个回答的内容,只改变请求落在哪。
- 速查:轮询公平但不看状态;负载水位比连接数更贴近大模型耗时;健康检查摘除故障实例;会话粘性保住缓存。
实例之外的那层调度还有自动扩缩容是怎么加减机器的?每一步都讲透、语义缓存是怎么判断「相似问题」的?、优先级队列是怎么排 VIP 的?权重怎么定和限流算法是怎么计数的?令牌桶的思路。
关于负载均衡,问得最多的三个
- 轮询真的不可用吗?:实例同质、请求均匀时够用;一旦耗时差异大,就要换按负载派发。
- 粘性会话和负载均匀冲突吗?:会,所以要给粘性加上限,别让一台机器被同一个用户的长对话拖住。
- 摘除的实例怎么发现它活了?:靠周期性健康检查重新探测,通过后再慢慢放回流量。


