10. 服务器调度
通常, HTTP 服务器尽早发送所有响应是有益的. 然而, 当在单个连接上服务多个请求时, 请求之间可能会竞争连接带宽等资源. 本节描述当存在这种竞争时, 服务器如何调度相互竞争的响应发送顺序时需要考虑的事项.
服务器调度是一个基于多种输入的优先级排序过程; priority signals (优先级信号) 只是其中一种输入. 实现选择或部署环境等因素也会发挥作用. 任意给定连接都可能具有许多动态排列组合. 因此, 无法描述一种通用调度算法. 本文档给出一些基础且非穷尽的建议, 说明服务器可以如何根据优先级参数采取行动. 它不会详细描述服务器如何将优先级信号与其他因素组合起来. 端点不能依赖基于优先级信号的特定处理. 表达优先级只是一种建议.
服务器在可能时 RECOMMENDED 遵循 urgency 参数 (Section 4.1), 先发送较高 urgency 的响应, 再发送较低 urgency 的响应.
incremental 参数表示客户端如何处理到达的响应字节. 服务器在可能时 RECOMMENDED 遵循 incremental 参数 (Section 4.2).
相同 urgency 的非 incremental 响应 SHOULD 按 stream ID 升序分配带宽来服务, 该顺序对应于客户端发出请求的顺序. 这样可确保客户端能够使用请求顺序来影响响应顺序.
相同 urgency 的 incremental 响应 SHOULD 通过在它们之间共享带宽来服务. incremental 响应的消息内容会随着分片或分块到达而被使用. 与接收单个资源的全部内容相比, 客户端从接收所有此类资源的部分内容中可能获得更大收益. 改善性能所需的资源部分大小各不相同. 某些资源类型会把关键元素放在前面; 其他资源则可以渐进式地使用信息. 本方案没有明确规定服务器应如何使用大小、类型或任何其他输入来决定如何确定优先级.
在某些场景中, 服务器可能需要在同一 urgency 级别调度多个 incremental 和非 incremental 响应. 严格遵循基于 urgency 和请求生成顺序的调度指导可能导致客户端结果并非最优, 因为较早的非 incremental 响应可能阻塞较晚发出的 incremental 响应的服务. 以下是这类挑战的示例:
-
在同一 urgency 级别, 一个针对大型资源的非 incremental 请求后面跟着一个针对小型资源的 incremental 请求.
-
在同一 urgency 级别, 一个长度不确定的 incremental 请求后面跟着一个非 incremental 大型资源.
服务器在可能时 RECOMMENDED 避免这种 starvation (饥饿). 具体方式由实现决定. 例如, 服务器可以基于内容大小等其他信息, 抢先发送某些 incremental 类型的响应.
server push (服务器推送) 的最优调度很困难, 尤其是在被推送资源与活跃并发请求竞争时. 服务器在调度时可以考虑许多因素, 例如被推送资源的类型或大小、触发推送的请求的优先级、活跃并发响应的数量、其他活跃并发响应的优先级等. 对于如何最好地应用这些因素, 并不存在通用指导. 过于简单的服务器可能以过高优先级推送并阻塞客户端请求, 或以过低优先级推送并延迟响应, 从而抵消 server push 的预期目标.
优先级信号是 server push 调度中的一个因素. 参数值默认值的概念在这里适用方式略有不同, 因为初始优先级没有显式客户端信号. 服务器可以应用源站响应中提供的优先级信号; 参见 Section 8 中给出的合并指导. 在缺少源站信号时, 应用默认参数值可能并非最优. 无论服务器决定如何调度被推送的响应, 它们都可以通过在 PUSH_PROMISE 或 HEADERS frame 中包含 Priority field, 向客户端表示预期优先级.
10.1. 具有多个后端连接的中介
服务 HTTP 连接的 intermediary (中介) 可能会将请求分散到多个后端连接上. 当它严格应用优先级排序规则时, 只要较高优先级的请求仍在传输中, 较低优先级的请求就无法取得进展. 这种阻塞可能传播到后端连接, 对端可能将其解释为连接停滞. 端点通常会实现针对停滞的保护, 例如在一段时间后突然关闭连接. 为降低这种情况发生的可能性, 中介可以避免严格遵循优先级排序, 而是为它转发的所有请求分配少量带宽, 使每个请求都能随时间取得一些进展.
类似地, 服务器 SHOULD 为充当 tunnel (隧道) 的流分配一定量的带宽.