6 月 6 日,IETF QUIC 和 HTTP 工作组成员 Robin Marx 宣布,经过 5 年的努力,HTTP/3 被标准化为 RFC 9114,这是 HTTP 超文本传输协议的第三个主要版本。同时,HTTP/2 也更新为 RFC 9113标准,HTTP/1.1 和通用 HTTP 语义和缓存概念在 RFC 9110-9112 中也得到了加强。
TCP 是 Internet 上使用和部署最广泛的协议之一,多年来一直被视为网络基石,随着HTTP/3正式被标准化,QUIC协议成功“上位”,UDP“取代”TCP成为基础协议,TCP究竟“输”在哪里?
HTTP/3 采用了谷歌多年探索的基于 UDP 的 QUIC 协议,原名叫 HTTP-over-QUIC,在 2018 年被 IETF 批准更名为 HTTP/3。目前,Cloudflare、Google Chrome、Firefox Nightly 均表示支持 HTTP/3。
为什么我们需要 HTTP/3?
很多人可能都会有这样一个疑问,为什么在 2015 年才标准化了 HTTP/2 ,这么快就需要 HTTP/3?
事实上,我们并不是真的需要新的 HTTP 版本,而是需要对底层传输控制协议(TCP) 进行升级。
TCP与HTTP的不解之缘
HTTP(超文本传输协议 1.0)的第一个正式版本在 1996 年完成。但是HTTP/1.0 没有充分考虑分层代理、缓存、长连接的需求和虚拟主机的影响。所以在一年后HTTP/1.1发布,这也是使用最广泛的版本。
在 HTTP/1.1 中, 浏览器通过 TCP 连接一次只能下载一个文件, 如果一个页面需要 10 个 js 文件, 那么这些文件将会按顺序下载。一个文件的延迟就会阻塞后面的其他内容, 也就是我们常说的队头阻塞。
2015年, HTTP 协议迎来了更新, HTTP/2发布。HTTP/2 的一大特点是多路复用。引入了二进制帧和流机制,允许使用单个 TCP 连接, 通过 Stream 并行下载资源, 提高了传输效率。然而HTTP/2的多路复用技术使得多个请求其实是基于同一个TCP连接的,因此在HTTP/2中,TCP队头阻塞造成的影响会更大,如果某一个请求造成了TCP队头阻塞,那么多个请求都会受到影响。
事实上,在丢包率高的环境中,HTTP/1.1 性能更好。
此外,发起 HTTP 请求时,需要经过 TCP 三次握手和四次挥手的过程,整个过程共需要 3 个 RTT 的时延才能发出请求数据。如果客户端和服务器相距遥远,则每RTT可能会花费超过 100 毫秒,从而导致明显的延迟。
RTT:往返时间(Round Trip Time),指一个请求从客户端浏览器发送一个请求数据包到服务器,再从服务器得到响应数据包的这段时间。RTT 是反映网络性能的一个重要指标。
几十年来,TCP 一直是网络的基石,但种种问题让大家不得不思考取代它的方法,这就是——QUIC,QUIC在几个关键方面与 TCP 有很大不同,直接在其上运行 HTTP/2 将非常困难。因此,HTTP/3 本身是对 HTTP/2 的一个相对较小的改编,以使其与新的 QUIC 协议兼容。
什么是QUIC协议
QUIC是一种通用、安全、多路复用的传输层新型网络协议,它的目标是取代TCP。
- 2012年,QUIC协议由当时还在谷歌任职的Jim Roskind开发。
- 2013年,QUIC正式对外公布。
- 2015年,QUIC被提交给IETF进行标准化。
但是直到六年以后,也就是2021年5月,IETF才发布了第一版标准化的QUIC,被命名为RFC 9000。同时,IETF还发布使用了QUIC的HTTP/3标准化版本。QUIC吸纳了很多与TCP类似的属性,还有TLS加密,将它们置于UDP传输之上的应用层中。
QUIC与 TCP 非常相似,除了 HTTP 和网页加载之外,还可以将其用于许多用例。例如,DNS、SSH、SMB、RTP 等都可以在 QUIC 上运行。
UDP+QUIC=最佳拍档
UDP 是最基本的传输协议。除了端口号(例如,HTTP 使用端口 80,HTTPS 使用 443,DNS 使用端口 53)之外,它实际上不提供任何特性。它不通过握手建立连接,也不可靠:如果UDP包丢失,它不会自动重传。UDP 的“尽力而为”方法不保证可靠性,无需等待握手,也没有 HoL 阻塞。在实践中,UDP协议主要用于实时性要求很高,但不要求完整性的应用,例如实时视频会议或者游戏等。它对于需要较低的预先延迟的情况也很有用,例如,DNS域名查找只需要一个来回就可以完成。
在 UDP 之上,QUIC 结合了 TCP 数十年的部署和实践经验,能够实现几乎所有的 TCP的特性。QUIC 的传输是绝对可靠的,可以通过流量控制和拥塞控制机制来防止过载,并且以比 TCP 更智能、更高效的方式实现了这些功能。
QUIC 对于TCP 的改进主要可归结为四个方面:QUIC 与 TLS 深度集成、QUIC 支持多个独立的字节流、QUIC 使用连接 ID、QUIC 使用帧(frame)。
QUIC 与 TLS 深度集成
TLS(传输层安全协议)负责保护和加密通过 Internet 发送的数据。当使用 HTTPS 时,纯文本 HTTP 数据首先由 TLS 加密,然后由 TCP 传输。1.2 及更低版本的TLS通常需要两次RTT,新版本的 TLS 1.3 只需一次RTT。
在互联网早期,加密流量在处理方面的成本很高,因此很多情况下并不是必要的。TLS 是一个完全独立的协议,可以选择是否在 TCP 之上使用,这也是区分 HTTP(没有TLS)和 HTTPS(有TLS)的原因。
随着时间的推移,我们对互联网安全的态度已经转变为“默认安全”。因此QUIC的设计者选择将加密深深地嵌入到 QUIC 本身中。虽然 TLS 1.3 仍然可以在 TCP 之上独立运行,但 QUIC 封装了 TLS 1.3。换句话说,没有 TLS 就无法使用 QUIC;QUIC(以及 HTTP/3)始终是完全加密的。此外,QUIC 还加密了几乎所有的数据包头字段。这为 QUIC 提供了几个好处:
- QUIC 对用户来说更安全:QUIC没有办法明文运行,因此网络攻击者的选择也更少。
- QUIC 的连接设置更快:虽然对于 TLS-over-TCP,两种协议都需要各自单独的握手,但 QUIC 将传输和加密握手合二为一,从而节省了一次往返时间。
- QUIC 更容易更新:如果在未来想为 QUIC 添加新功能,我们只必须更新终端设备,而不是所有的中间件。
QUIC 支持多个独立的字节流
对于 HTTP/1.1,资源加载过程非常简单,因为每个文件都有自己的 TCP 连接。例如,如果我们有文件 A、B、C,我们将有三个 TCP 连接。第一个将看到 AAAA 的字节流,第二个 BBBB,第三个 CCCC(每个字母重复都是一个 TCP包)。这可行,但也非常低效,因为每个新的连接都会产生一些开销。
HTTP/2 的主要目标之一就是改善这种情况。HTTP/2 协议不再为每个文件打开一个新的 TCP 连接,而是通过单个 TCP 连接下载不同的资源。这是通过多路复用不同的字节流来实现的。举例来看,同样是传输A、B、C三个文件,我们将获得一个 TCP 连接,传入的数据形式可以是 AABBCCAABBCC等。通常情况下,使用HTTP/2 跟HTTP/1.1 一样快或快一点,但开销要少得多。
HTTP/2的多路复用机制解决了HTTP层的队头阻塞问题,但是在TCP层仍然存在队头阻塞问题。
TCP协议在收到数据包之后,这部分数据可能是乱序到达的,但是TCP必须将所有数据收集排序整合后给上层使用,如果其中某个包丢失了,就必须等待重传,从而出现某个丢包数据阻塞整个连接的数据使用。例如,HTTP 级别的 AABBCCAABBCC,在TCP 眼里它只是 XXXXXXXXXXXX ,如果此时B丢失,它不会发现到底是谁丢失,而是整个重传。
解决传输层的队头阻塞是 QUIC 的主要目标之一。与 TCP 不同,QUIC 清楚地意识到它正在复用多个独立的字节流。因此,QUIC 可以在每个流的基础上执行丢包检测和恢复逻辑。
在上述场景中,QUIC 只会保留 B 的数据,并且尽快将 A 和 C 的数据传递到 HTTP/3 层。
QUIC 使用连接 ID
一个 TCP 连接是由四元组(源 IP 地址,源端口,目标 IP 地址,目标端口)确定的,这意味着如果 IP 地址或者端口变动了,就会导致需要 TCP 与 TLS 重新握手,这不利于移动设备切换网络的场景,比如 4G 网络环境切换成 WIFI。这些问题都是 TCP 协议固有的问题。
为了解决这个问题,QUIC 引入了一个名为连接ID(connection identifier,CID)的新概念。每个连接在 4 元组之上分配了另一个编号,该编号在两个端点之间唯一标识它。
更重要的是,因为这个 CID 是在 QUIC 本身的传输层定义的,所以在网络之间移动时它不会改变。通过这种设置,即使 4 元组中的某一项发生了变化,QUIC 服务器和客户端只需查看 CID即可知道它是同一个旧连接,可以继续使用它。不需要重新握手,下载状态可以保持原样。这个功能通常称为连接迁移。
QUIC 使用帧(frame)
与 TCP 不同,QUIC 不使用单个固定的数据包头来发送所有协议元数据。相反,QUIC 具有短的数据包头,并在数据包有效载荷内使用各种“帧”来传达额外信息。例如,一个ACK帧(用于确认)、一个NEW_CONNECTION_ID帧(用于帮助建立连接迁移)和一个STREAM帧(用于承载数据),如下图所示:
这主要是一种优化,因为不是每个包都携带所有可能的元数据(因此TCP包头通常会浪费相当多的字节)。使用帧还有一个好处,在未来将新帧类型定义为QUIC的扩展将非常容易。例如,一个非常重要的框架是DATAGRAMframe,它允许通过加密的 QUIC 连接发送不可靠的数据。
总结
总的来说,QUIC相较于TCP有许多优点,但是想要真正实现全面推广也是存在一些困难的。很多企业、运营商和组织对53端口(DNS)以外的UDP流量会进行拦截或者限流(这些流量常被滥用于攻击),因此基于UDP的QUIC协议的传输可能会受到屏蔽。此外,很多中间设备对于UDP的支持和优化程度也并不高。
不过,尽管还存在一些未知的困难,但HTTP/3.0的时代一定会到来的!