大模型服务里,请求和请求之间也有先后之分:付费用户的高峰提问、免费的偶发调用,如果排同一条队,体验就被拉平了。优先级队列就是给请求分等级、按等级安排出队顺序的那套机制,VIP 排前面,普通请求不掉队。这套机制看着简单,分级、排序、防饿三步各有门道。
VIP 优先是怎么被定义的
等级并非凭空标出来的,来源通常有三类:账号档位、接口类型、任务特征。会员请求标高一级,实时对话标高一级,后台批量任务标低一级。进来的是请求附带的属性,发生的是规则匹配,出去的是每条请求头上的优先级标签。
标签打完还要过冲突处理:一条请求既属高档位又是批任务,取高取低要有明确规则,通常按业务影响定,谁停下来影响大就听谁的。规则定了就稳定执行,标签体系最怕同一类请求时高时低,那会让排队失去预期。
标签本身要轻量:一个整数或短枚举就够,别把整套用户画像塞进请求头。标签跟着请求走完整条链路,网关、队列、日志都要能读它,格式一旦定下就别频繁改。等级档位也不宜太多,三五档足够,太细反而选不出来,档位之间差距要拉得开,用户才感知得到差别。
队列内部的排序与出队
队列内部常用堆结构:每次出队取当前等级最高的一条,同级内部按先来后到。进来的是带标签的请求,发生的是入堆与调整,出去的是队头请求。堆调整只动少量元素,插入与出堆的代价都很小,队列再长也不拖慢出队。
出队节奏要和下游算力咬合:负载均衡每空出一个位置,队列就放一条最高级的过去。两边咬合得好,VIP 的等待就短;咬合得差,标签打得再准也白搭。队列深度还要设上限,堆得太深再高的等级也等不起。
你在豆包、通义千问这类大模型产品里,高峰期对话依然跟得上节奏,而报告生成、批量摘要这类后台任务慢一些才完成,背后往往就是优先级队列在排序。同一账号在不同入口的请求也可能带不同标签,网页端和客户端各有默认等级,混用时以请求头里实际带的为准。
优先级高了会饿死谁
等级悬殊时最怕低级请求长期排不上:高优先级源源不断,低优先级等到超时也没轮上,这叫饥饿。对策是老化机制:排队越久等级缓步上调,到点必须放行,谁也不能永远排队。
另一条是配额保底:无论队列多挤,每一档都留固定比例的出队名额,低级请求慢但不至于断流。两条合用,饥饿问题基本压得住。饥饿的判定要靠数据说话:队列里每条请求排了多久有记录,最老的那条超过阈值就该报警。老化上调的速度也有讲究,调太快高等级请求被反超,调太慢等于没防,常见做法是每等一分钟升一小级,同级内部仍是先来后到。
防饥饿的三道手段,做法和注意点。
| 手段 | 具体做法 | 注意点 |
|---|---|---|
| 老化机制 | 排队越久等级缓步上调,到点必须放行 | 常见每等一分钟升一小级;调太快高等级请求被反超,调太慢等于没防 |
| 配额保底 | 无论队列多挤,每一档都留固定比例的出队名额 | 低级请求慢但不至于断流 |
| 饥饿判定 | 记录队列里每条请求排了多久 | 最老的那条超过阈值就该报警 |
等级体系还要定期复盘:标签打得准不准,看排队数据就知道,高等级请求的等待若和普通请求拉不开差距,说明分级没起作用,要么档位要调,要么出队逻辑要查。
- 速查:等级来自档位、接口、任务三类属性;堆按级出队、同级先来后到;老化机制防饥饿;配额保底防断流;队列深度要设上限。
队列只是调度的一层,上下游的配合还有负载均衡是怎么分流请求的?多实例配合、自动扩缩容是怎么加减机器的?每一步都讲透、限流算法是怎么计数的?令牌桶的思路和批大小和延迟的取舍是怎么权衡的?。
关于优先级队列的三个常问问题
- VIP 请求一定秒回吗?:不一定,等级只决定排序,前面还有限流和算力上限兜着,高峰时 VIP 也要排队,只是队更短。
- 等级能动态变吗?:能,老化就是最常见的动态调整,业务侧也可以按时间窗临时抬级,抬级要留记录,事后可追溯。
- 普通用户会被彻底挤掉吗?:不会,配额保底加老化机制,低级请求慢而不死。


