翻译、编辑:Alex
技术审校:刘连响
本文来自_Smashing Magazine_,原文链接:
https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/
Robin讲HTTP/3 #005#
到现在为止,我们主要对比了QUIC和TCP中的性能特性。那么HTTP/3和HTTP/2之间的区别是什么?我们在第一部分讨论过,HTTP/3实际上是HTTP/2-over-QUIC,所以新版本中并没有推出什么真正重要的新特性。这与从HTTP/1到HTTP/2不同,其中的变化更多,并推出了如头压缩、流优先级和服务器推送等新特性,HTTP/3中依然保留了这些特性。
HTTP/3与HTTP/2之间的重要差异在于它们的底层实现方式。
QUIC的队头阻塞消除在其中起了很大作用。我们之前讨论过,数据流B的丢失不再意味着数据流A和C必须等待B的重传(像它们在TCP上那样)。因此,如果A、B和C每一个都按照那个顺序发送QUIC数据包,那么它们的数据很可能按照A、C和B的顺序传送到浏览器(并由浏览器处理)。换言之,QUIC不再像TCP那样对不同的数据流完全排序!
这成了HTTP/2的一个问题,因为HTTP/2所设计的许多特性(这些特性使用分散在数据块中的特殊控制消息)都要依赖TCP的严格排序。而在QUIC中,这些控制消息可以按照任何顺序到达,甚至可能会使这些特性发挥与预期相反的作用。本文无需详述这其中的技术细节,但这篇论文的前半部分会告诉你它是多么的复杂[1]。
因此,必须针对HTTP/3更改这些特性的内部机制和实现。一个具体的例子是HTTP头压缩,它降低了较大的重复HTTP头(比如cookies和user-agent字符串)所产生的开销。HTTP/2通过HPACK[2]实现了HTTP头压缩,而在HTTP/3中,这一系统被重新设计为更加复杂的QPACK[3]。两个系统以不同方式提供相同的功能(头压缩)。在Litespeed上你可以找到关于这个问题很棒的深度技术讨论和图表[4]。
推动数据流多路复用的优先级特性也是如此,我们在之前的文章中已经简单讨论过。为了实现优先级,HTTP/2使用了一个复杂的依赖树(dependency tree),该设置尝试对所有网页资源及其相互关系建模(想了解更多信息,你可以观看《HTTP资源优先级终极指南》[5]的演讲)。在QUIC上直接使用这个系统很可能导致非常错乱的依赖树布局,因为将每个资源添加到树上都需要一个独立的控制消息。
此外,事实证明,完全没有必要使用这么复杂的方法,因为它会导致实现错误和低效问题[6],以及许多服务器上的性能不佳[7]。因此,需要为HTTP/3重新设计一种更加简单的优先级系统[8]。这种更直接的设置使得一些高级场景难以或不可能实现(比如,单一连接上代理流量来自多个客户端的情况),但仍然为网页加载优化提供了广泛的选项。
再来重申一下,这两种方法提供相同的功能(引导数据流的多路复用),但HTTP/3更简单的设置将减少实现错误。
最后,还有服务器推送。服务器可以通过这一特性发送HTTP响应,而无需先等待明确的请求。理论上,这会带来出色的性能提升。但实际中却被证实,服务器推送很难被正确[9]使用且无法获得一致的实现[10]。结果就是,它很可能将从Google Chrome中移除[11]。
尽管如此,服务器推送依然被HTTP/3定义为特性[12](虽然少有实现支持它)。它的内部工作方式并没有像前两个特性那样发生很大的变化,但它同样适应了QUIC的非确定排序。不过遗憾的是,这并不会解决那些长期存在的问题。
这一切意味着什么?
正如我们之前所说,HTTP/3的大部分潜力来自底层的QUIC,而非HTTP/3本身。虽然HTTP/3的内部实现非常不同于HTTP/2,但