后端面试:如何用 HTTP Priority 设计资源调度策略?
题干与适用场景
一个页面同时请求 HTML、关键 CSS、字体、图片和后台数据。移动网络带宽有限,团队希望用 HTTP Priority 让关键资源更早完成,却担心代理覆盖优先级、低优先级请求饥饿、缓存命中绕过调度,以及丢包重传改变顺序。请设计服务端与代理的调度策略,覆盖 HTTP/1.1、HTTP/2、HTTP/3 和验证方案。
RFC 9218 定义了与协议版本无关的 Priority 头,也定义了 HTTP/2 和 HTTP/3 的重新排序帧。它表达的是客户端和服务器的偏好,不是必须遵守的交付承诺。强回答会把信号、调度器、缓存和传输层分开,并说明每一层可以拒绝或改写什么。
面试官考察点
- 是否知道 urgency 的范围是 0 到 7,数值越小优先级越高,默认请求值为 3。
- 是否能解释 incremental 对同一 urgency 资源的并发分片和完成时间的影响。
- 是否区分 HTTP/1.1 的顺序请求与 HTTP/2、HTTP/3 的多路复用调度。
- 是否把 Priority 当提示而非 SLA,并处理恶意或错误客户端的优先级声明。
- 是否考虑缓存命中、代理重排、QUIC 重传、公平性与跨连接竞争。
- 是否能设计可回退的灰度和按用户体验结果验收的指标。
回答前需要澄清的问题
- 目标是降低首屏 LCP、缩短某个 API 的尾延迟,还是提高后台吞吐?目标不同会改变优先级和指标。
- 资源是否同一连接、同一 CDN 节点和同一缓存键?跨连接时单连接优先级无法直接比较。
- 哪些资源能增量处理?CSS、完整字体和不可分块的压缩对象通常不应仅因高 urgency 就并发切片。
- 代理是否允许转发请求头、响应头和 PRIORITY_UPDATE?所有链路是否使用 HTTP/2 或 HTTP/3?
- 是否有租户、用户或安全边界,防止低价值请求伪装成最高优先级?
30 秒回答框架
我会先把目标定为用户可感知的完成时间,再给资源分类和默认优先级。客户端的 Priority 只作为输入,服务端按资源类型、缓存状态、连接和公平性重新计算。urgency 0 到 7 表达相对顺序,incremental 只给能边到边处理的响应。HTTP/1.1 采用连接内请求顺序,HTTP/2 和 HTTP/3 使用调度器及必要的重新排序帧。缓存命中、重传和跨连接带宽另行处理。灰度时同时看 LCP、关键资源完成时间、后台尾延迟、饥饿比例和带宽,异常就关闭改写策略。
分步骤深入解答
1. 先把业务目标转成调度目标
首屏 HTML、阻塞渲染的 CSS 和关键字体追求尽快完成;大图片可低一些 urgency;分析上报和预取应避免争抢;后台 API 不能因为用户看不见就无限等待。为每类资源定义最大等待时间和可接受的带宽份额,而不是只写“关键请求优先”。
2. 解释 Priority 两个参数
u 是 urgency,0 最高、7 最低,客户端请求默认值为 3。i 表示响应能否被增量处理;存在 i 时,服务器可以把同 urgency 的带宽分给多个资源,让它们都更早开始,但每个资源完成得可能更晚。没有 i 时,更适合按顺序发送不可增量消费的对象。
GET /style.css HTTP/1.1
Host: example.test
Priority: u=1
GET /hero.jpg HTTP/1.1
Host: example.test
Priority: u=4, i服务端响应也可以提供优先级提示给下游中间层;缺少响应头表示服务器没有改变客户端优先级。未知参数应被忽略,不能把客户端提供的值当成权限或计费依据。
3. 按协议版本选择调度边界
HTTP/1.1 没有内建的多路复用优先级,服务端主要受连接内顺序、并发连接数和队列影响。HTTP/2 与 HTTP/3 在一条多路复用连接上共享带宽,调度器可以按 urgency 和 incremental 选择下一个数据片段。HTTP/2、HTTP/3 还能通过对应的 PRIORITY_UPDATE 机制改变已发送请求的偏好,但实现不保证立即或严格执行。
4. 处理缓存与代理
缓存命中可能直接返回,不经过源站的业务调度;需要把优先级影响限制在传输和缓存填充阶段,不能让普通 Priority 头改变对象授权或缓存键。代理可以合并客户端连接、建立不同的后端连接或重写响应优先级,因此应在每个边界记录原始值、最终值和选择原因。缓存规则仍由 Cache-Control、Vary 等字段决定。
5. 处理重传与公平性
QUIC 和 TCP 都会重传丢失数据。高 urgency 的新数据不一定应该压过低 urgency 的重传,因为重传可能解除一个已开始响应的阻塞;RFC 9218 把这个取舍交给传输实现和应用策略。跨连接竞争时,单连接内的 u=0 不能保证获得全局最高带宽。调度器应设置每连接配额、老化时间和最大连续发送量,避免后台请求永久饥饿。
6. 防止优先级滥用与错误传播
客户端可把所有请求标成 u=0,因此服务端要按资源白名单、认证主体、页面阶段和历史行为校正。可以限制最高 urgency、按租户配额、对未知资源回到默认值,并记录覆盖事件。跨代理传递时保留语义而非盲目复制字符串;若下游不理解信号,应安全忽略而不改变响应正确性。
7. 灰度、回退与验收
先选择固定页面和低风险 CDN 节点,对一部分连接启用服务端改写。比较同一网络、设备、缓存状态和资源集合下的对照组,记录 LCP、关键 CSS 完成时间、字体阻塞时长、后台 p95/p99、首字节时间、重复下载、连接利用率和低优先级最长等待。任何用户体验改善都要和错误率、带宽成本及跨租户公平一起判断;如果调度器异常,立即恢复默认优先级。
高质量示范回答
我会先定义首屏完成和后台请求的目标,再把资源分成 HTML、阻塞 CSS、字体、可增量媒体和后台数据。客户端 Priority 只作为提示:我会按资源白名单、页面阶段、缓存状态和租户配额校正,默认使用 urgency 3,关键资源降低数值,后台请求提高数值;只有能边到边消费的响应才使用 incremental。
HTTP/1.1 主要靠连接和队列顺序;HTTP/2、HTTP/3 由多路复用调度器按优先级发送,并按需使用重新排序帧。缓存命中不应改变授权和缓存键,代理要记录原始与最终优先级。重传不能盲目让位给新数据,我会设置连接配额、老化和最大连续发送量避免饥饿。灰度对比 LCP、关键资源完成、后台尾延迟、带宽和低优先级等待;指标恶化就关闭服务器改写。
常见错误
- 把
Priority: u=0当作必须先完成的 SLA → 服务端仍要考虑拥塞、缓存和重传 → 把它作为调度输入并定义可观测目标。 - 把
incremental当成“更快完成” → 并发分片会让单个对象完成更晚 → 只给可增量消费且有用户收益的响应使用。 - 让客户端优先级改变缓存键或授权 → 造成缓存碎片或安全越权 → 保持缓存与权限契约独立。
- 只分析一条 HTTP/2 连接 → 跨连接竞争可能反转结果 → 按连接、节点、网络和租户切片验证。
- 让高优先级重传永远压过其他数据 → 新响应或低优先级流可能永久等待 → 加入重传策略、配额和老化。
- 只看 LCP → 后台尾延迟和带宽成本可能恶化 → 同时设置用户、可靠性、公平性和成本门槛。
追问及应对
所有客户端都发送 u=0 怎么办?
把值视为不可信提示,按资源类型、页面阶段、认证主体和租户配额重算;未知或异常请求回到默认值,并记录覆盖原因。
incremental 是否总能改善体验?
不能。它让同 urgency 的响应共享带宽,可能让多个对象更早开始,却让每个对象更晚完成。只在消费者能处理部分数据且首字节收益重要时启用。
缓存命中还需要 Priority 吗?
命中通常绕过源站业务队列,但代理仍可能在连接上调度传输。Priority 不能进入授权逻辑或无理由改变缓存键;应分别观测命中、填充和发送阶段。
丢包时应先发重传还是高 urgency 新数据?
没有脱离上下文的答案。重传可能解除已开始响应的阻塞,高 urgency 新数据可能更影响用户;应结合流依赖、应用增量能力、拥塞状态和可复算的体验目标决定。
HTTP/1.1 能实现同样的优先级吗?
没有 HTTP/2 那种多路复用优先级树。可以在服务端队列、连接并发和资源排序上近似实现,但必须把它当实现策略,并验证队头阻塞和连接竞争。
如何证明没有低优先级饥饿?
记录每个请求的排队和首次发送时间,按资源、连接和租户计算最大等待及 p99;在压力测试中持续注入高 urgency 流,确认老化、配额或截止时间能让低优先级流获得服务。