系统设计面试:如何为控制面 API 设计优先级与公平调度?
题干与适用场景
控制面 API 同时承载健康检查、控制器写入、租户查询和长时间 watch。突发流量或单个租户的失控请求会拖慢所有请求。请设计一套优先级与公平调度机制,说明分类、并发上限、排队、超时和降级如何协同。
面试官考察什么
- 能否把“重要”转换为可审计的请求分类,而不是给某个团队永久特权。
- 能否用并发席位、队列和配额保护控制面,而不只是在入口加一个限流器。
- 能否解释公平的粒度、长请求的占用、租户隔离和故障时的降级。
- 能否用延迟、拒绝率、队列年龄和控制器恢复时间验证方案。
回答前要澄清的问题
- 哪些请求是安全关键写入,哪些是可延后的读取或 watch?
- 公平按租户、身份、工作负载还是资源类型计算?是否允许管理员紧急通道?
- 目标是保护 API server、下游数据库,还是两者都要保护?
- 长请求是否消耗多个并发席位,断连后如何释放?
- 超载时允许返回 429,还是必须保留部分成功率和重试提示?
30 秒回答框架
我会先按身份、动词和资源把请求映射到有限的优先级流,再为每条流设置并发席位和公平队列。高优先级只获得有上限的保底容量,低优先级在压力下排队或拒绝。长请求单独分类并计入持续占用,所有拒绝都带可操作的重试信号。最后用 p99、队列年龄、429 比例、下游饱和度和关键控制器恢复时间做闸门。
分步骤深入解答
第一步:建立可解释的请求分类
分类键应来自可验证的身份、HTTP 动词、目标资源和请求是否长运行。不要让客户端任意提交“高优先级”字段。将控制器写入、节点心跳、管理员查询和批量列表拆成不同流,并记录命中规则。
第二步:把容量建模为席位
用席位表示同时占用的服务能力,而不是只按请求数计数。快查询可占一个席位,慢查询或 watch 需要更多席位,完成或取消时释放。每条优先级设置 nominal limit,同时保留总席位上限,避免各流保底相加超过实际容量。
第三步:在每条优先级内做公平排队
同一优先级内再按租户或流标识做加权公平队列,防止一个租户填满该优先级。调度器选择有等待请求且未超过 current limit 的流;连续超时的请求提高年龄权重,但不能绕过全局席位上限。
第四步:处理长运行请求和下游依赖
watch、日志尾读等请求应有独立预算、最大持续时间和心跳取消。对数据库、缓存或外部服务设置独立并发舱壁;入口队列不能把压力无限传给下游。重试只用于可重试错误,并使用指数退避和抖动。
第五步:定义超载动作
压力升高时先暂停低优先级新请求,再限制批量列表和昂贵过滤,最后对无法排队的请求返回 429。响应应携带明确的等待提示,客户端也必须设置重试上限、抖动和截止时间。安全关键写入若不能接受丢弃,应进入持久队列并返回可查询的操作 ID。
第六步:观测公平性而非只看平均延迟
按优先级、租户、请求类型分别监控 p50、p99、队列年龄、席位占用、429、取消和下游错误。加入最大等待时间、关键写入成功率、恢复时间和租户间服务差异的告警。压测要覆盖单租户洪峰、长请求占满、规则误分类和控制器恢复。
第七步:安全演进和回滚
先以只观测模式记录新分类命中,再逐步启用限额。配置版本要可审计、可回滚,并保留紧急但受限的运维通道。改变席位或优先级时同时比较下游容量和历史队列分布,避免只看 API 层指标。
高质量示范回答
我会把控制面容量建模成全局席位池,按身份、动词、资源和长运行属性把请求映射到优先级流。控制器写入和节点心跳有保底席位,但保底总和不超过安全容量;普通租户查询在同一优先级内按租户做公平队列。watch 单独计费并有最长持续时间,取消时立即释放席位。负载升高时依次暂停批量读取、限制昂贵过滤,对无法排队的请求返回 429 和等待提示;写入若必须完成则落到持久队列。上线前记录分类命中和各租户队列年龄,启用后以关键写入成功率、p99、429、下游饱和度和恢复时间做回滚闸门。
常见错误
- 只设置全局 QPS,导致长请求仍能耗尽并发。
- 把管理员或某个租户设为无限优先级,造成不可审计的饥饿。
- 只按请求数计费,不区分快查询、列表和 watch 的资源占用。
- 让所有客户端立即重试 429,形成同步重试风暴。
- 只看平均延迟,忽略低优先级队列的最大等待时间。
- 修改限额时没有灰度、版本和回滚路径。
追问及应对
追问一:为什么不能只用令牌桶?
令牌桶限制进入速率,却不表达不同请求的并发成本、长请求占用或租户间公平。它可作为入口层的一部分,但需要席位和队列补足。
追问二:高优先级会不会饿死低优先级?
会,除非高优先级也有上限,并在其内部和全局设置保留比例、最大连续服务量或老化策略。紧急通道必须受审计和容量约束。
追问三:watch 应该算几个席位?
不能固定回答。应以连接数、事件速率、序列化成本和下游查询压力测量,给出保守基线并通过压测校准;超时和断连必须释放席位。
追问四:429 的重试时间由谁决定?
服务端根据预计恢复时间给出最小等待提示,客户端再叠加指数退避、抖动和截止时间。提示不是容量保证,客户端仍要限制重试次数。
追问五:如何证明公平?
定义租户级服务目标,例如在同一优先级内的席位份额、最大队列年龄和完成率,并在单租户洪峰与混合负载下比较分布,而不是只报告全局均值。
追问六:规则误把关键写入归到低优先级怎么办?
先保留规则命中日志和人工审计,配置以版本化方式发布;发现关键写入成功率下降时立即回滚分类版本,并保留受限的安全通道处理存量任务。