从 HTTP/1.1 到 HTTP/2,HTTP 协议一直都是使用 TCP 作为传输协议。
然而,就在最新的 HTTP/3,HTTP 就直接把 TCP 抛弃了,向孤立无援的 UDP 伸出了援手,基于 UDP 协议的基础上,在应用层实现了一个可靠的传输协议 —— QUIC。
很多同学可能就好奇了,HTTP 都用 TCP 都用了几十年了,而且 TCP 已经是那么完善的可靠传输协议了,又有超时重传、按序接收、流量控制、拥塞控制这些特性,怎么突然就把 TCP 抛弃了?到底是 TCP 哪里做的不够好?是不是鸡蛋里挑骨头了?
所以,今天就跟大家聊聊,TCP 那些不够“好”的原因。
TCP 存在队头阻塞问题
TCP 队头阻塞的问题要从两个角度看,一个是发送窗口的队头阻塞,另外一个是接收窗口的队头阻塞。
1、发送窗口的队头阻塞。
TCP 发送出去的数据,都是需要按序确认的,只有在数据都被按顺序确认完后,发送窗口才会往前滑动。举个例子,比如下图的发送方把发送窗口内的数据全部都发出去了,可用窗口的大小就为 0 了,表明可用窗口耗尽,在没收到 ACK 确认之前是无法继续发送数据了。
接着,当发送方收到对第 32~36 字节的 ACK 确认应答后,则滑动窗口往右边移动 5 个字节,因为有 5 个字节的数据被应答确认,接下来第 52~56 字节又变成了可用窗口,那么后续也就可以发送 52~56 这 5 个字节的数据了。
但是如果某个数据报文丢失或者其对应的 ACK 报文在网络中丢失,会导致发送方无法移动发送窗口,这时就无法再发送新的数据,只能超时重传这个数据报文,直到收到这个重传报文的 ACK,发送窗口才会移动,继续后面的发送行为。
举个例子,比如下图,客户端是发送方,服务器是接收方。
客户端发送了第 5~9 字节的数据,但是第 5 字节的 ACK 确认报文在网络中丢失了,那么即使客户端收到第 6~9 字节的 ACK 确认报文,发送窗口也不会往前移动。
此时的第 5 字节相当于“队头”,因为没有收到“队头”的 ACK 确认报文,导致发送窗口无法往前移动,此时发送方就无法继续发送后面的数据,相当于按下了发送行为的暂停键,这就是发送窗口的队头阻塞问题。
2、接收窗口的队头阻塞。
接收方收到的数据范围必须在接收窗口范围内,如果收到超过接收窗口范围的数据,就会丢弃该数据,比如下图接收窗口的范围是 32 ~ 51 字节,如果收到第 52 字节以上数据都会被丢弃。
接收窗口什么时候才能滑动?当接收窗口收到有序数据时,接收窗口才能往前滑动,然后那些已经接收并且被确认的「有序」数据就可以被应用层读取。
但是,当接收窗口收到的数据不是有序的,比如收到第 33~40 字节的数据,由于第 32 字节数据没有收到, 接收窗口无法向前滑动,那么即使先收到第 33~40 字节的数据,这些数据也无法被应用层读取的。只有当发送方重传了第 32 字节数据并且被接收方收到后,接收窗口才会往前滑动,然后应用层才能从内核读取第 32~40 字节的数据。
好了,至此发送窗口和接收窗口的队头阻塞问题都说完了,这两个问题的原因都是因为 TCP 必须按序处理数据,也就是 TCP 层为了保证数据的有序性,只有在处理完有序的数据后,滑动窗口才能往前滑动,否则就停留。
- 停留「发送窗口」会使得发送方无法继续发送数据。
- 停留「接收窗口」会使得应用层无法读取新的数据。
其实也不能怪 TCP 协议,它本来设计目的就是为了保证数据的有序性。
HTTP/2 的队头阻塞
HTTP/2 通过抽象出 Stream 的概念,实现了 HTTP 并发传输,一个 Stream 就代表 HTTP/1.1 里的请求和响应。
在 HTTP/2 连接上,不同 Stream 的帧是可以乱序发送的(因此可以并发不同的 Stream ),因为每个帧的头部会携带 Stream ID 信息,所以接收端可以通过 Stream ID 有序组装成 HTTP 消息,而同一 Stream 内部的帧必须是严格有序的。
但是 HTTP/2 多个 Stream 请求都是在一条 TCP 连接上传输,这意味着多个 Stream 共用同一个 TCP 滑动窗口,那么当发生数据丢失,滑动窗口是无法往前移动的,此时就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞。
没有队头阻塞的 QUIC
QUIC 也借鉴 HTTP/2 里的 Stream 的概念,在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (Stream)。
但是 QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口。
假如 Stream2 丢了一个 UDP 包,也只会影响 Stream2 的处理,不会影响其他 Stream,与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。
TCP 建立连接的延迟
对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手(1RTT),再 TLS 握手(2RTT),所以需要 3RTT 的延迟才能传输数据,就算 Session 会话服用,也需要至少 2 个 RTT,这在一定程序上增加了数据传输的延迟。
TCP 三次握手和 TLS 握手延迟,如图:
HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。
但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,因为 QUIC 也是应用层实现的协议,所以可以将 QUIC 和 TLS 协议握手的过程合并在一起,QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。
如下图右边部分,HTTP/3 当会话恢复时,有效负载数据与第一个数据包一起发送,可以做到 0-RTT(下图的右下角):
升级 TCP 的工作很困难
TCP 协议是诞生在 1973 年,至今 TCP 协议依然还在实现更多的新特性。
但是 TCP 协议是在内核中实现的,应用程序只能使用不能修改,如果要想升级 TCP 协议,那么只能升级内核。
而升级内核这个工作是很麻烦的事情,麻烦的事情不是说升级内核这个操作很麻烦,而是由于内核升级涉及到底层软件和运行库的更新,我们的服务程序就需要回归测试是否兼容新的内核版本,所以服务器的内核升级也比较保守和缓慢。
很多 TCP 协议的新特性,都是需要客户端和服务端同时支持才能生效的,比如 TCP Fast Open 这个特性,虽然在2013 年就被提出了,但是 Windows 很多系统版本依然不支持它,这是因为 PC 端的系统升级滞后很严重,Windows Xp 现在还有大量用户在使用,尽管它已经存在快 20 年。
所以,即使 TCP 有比较好的特性更新,也很难快速推广,用户往往要几年或者十年才能体验到。
相反,QUIC 是处于应用层的,所以如果升级 QUIC 协议的话,其实就是像升级软件一样轻松。而且,QUIC 可以针对不同的应用设置不同的拥塞控制算法,这样灵活性就很高了,这是 TCP 做不到的,因为 TCP 更改拥塞控制算法是对系统中所有应用都生效,无法根据不同应用设定不同的拥塞控制策略。
网络迁移需要重新建立 TCP 连接
基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。
那么当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立 TCP 连接。
而建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,给用户的感觉就是网络突然卡顿了一下,因此连接的迁移成本是很高的。
QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。
总结
HTTP/3 抛弃 TCP 后,基于 UDP 实现的可靠传输 QUIC 协议,带来这四点好处:
- 降低连接耗时:在客户端有缓存的情况下实现0-RTT建立连接
- 更灵活的拥塞控制:在用户态可以为每个请求配置不同的拥塞控制策略
- 无队头阻塞的多路复用:每个请求流独立拥有滑动窗口,互不影响
- 连接迁移:网络切换不会中断数据传输
不过, HTTP/3 也面临了一些挑战,QUIC 基于 UDP 协议在用户空间实现的可靠传输协议,如果一些网络设备无法识别出 QUIC 协议,那么在这些网络设备的眼里它就是一个 UDP 协议。
而几乎所有的电信运营商都会“歧视” UDP 数据包,原因也很容易理解,毕竟历史上几次臭名昭著的 DDoS 攻击都是基于 UDP 的。国内某城宽带在某些区域更是直接禁止了非 53 端口的UDP数据包,而其他运营商即使没有封禁 UDP,也是对 UDP 进行严格限流的。
自 2013 年 QUIC 被正式公开以来,到 2023 年已经发展了差不多 10 年,目前网上已经有了不少热门开源的项目,除去带头大哥 Google 在完成了对自身搜索引擎的支持,还同时拉上了 Gmail 、YouTube 等站点。但对于国内的绝大部分站点来说,大部分还是 HTTP/2 协议,HTTP/3 之路,似乎还停留在东土大唐。
HTTP/3是最新的超文本传输协议,它是基于QUIC(Quick UDP Internet Connections)协议开发的。HTTP/3是HTTP/2的后继者,可以有效地提高网页加载速度、改善安全性,并提供更好的流控制功能。
HTTP/3是由Internet Engineering Task Force(IETF)标准化的,旨在通过重新设计协议来克服TCP协议的一些限制。QUIC协议可以提供比TCP更高的可靠性(尽管QUIC 基于 UDP,但它在应用层实现了可靠的传输机制,如数据包确认、重传、拥塞控制等)和更好的性能(这是因为它是基于UDP协议而不是TCP协议构建的)。
相比于HTTP/2,HTTP/3有许多新的特性和改进。例如,HTTP/3使用QUIC协议中的快速连接建立机制,可以更快地建立连接。另外,HTTP/3可以同时处理多个请求和响应,从而提高了并发处理能力。
HTTP/3的特性
HTTP/3 在保留 HTTP/2 的许多优点的基础上,引入了一系列新特性和改进。以下是 HTTP/3 的主要特性:
- 基于 QUIC 协议:HTTP/3 放弃了基于 TCP 的底层传输协议,而选择了 QUIC(Quick UDP Internet Connections)协议。QUIC 是一个基于 UDP 的可靠传输协议,设计用于解决 TCP 在高延迟和丢包率较高的网络环境下的性能问题。QUIC 的引入使 HTTP/3 具有更低的延迟和更好的拥塞控制能力。
- 避免队头阻塞:TCP 传输中,一个连接的数据包丢失会导致后续的数据包被阻塞,即使它们属于不同的请求。这称为队头阻塞(Head-of-line blocking)。QUIC 通过在单个连接中多路复用请求来解决这个问题。在 QUIC 中,一个数据包的丢失不会影响其他独立流的数据传输。
- 快速建立连接:TCP 需要一个三次握手过程来建立连接,而且在使用 TLS 时还需要额外的往返。QUIC 支持零往返时间(0-RTT)连接建立,可以显著降低连接建立所需的时间,尤其是在高延迟的网络环境下。
- 内置加密:QUIC 协议将加密作为其核心功能,不再依赖单独的 TLS 层。这不仅可以提高安全性,而且可以简化协议栈,提高传输性能。
- 更好的拥塞控制:QUIC 实现了更先进的拥塞控制算法,能够更好地应对网络拥塞,提高数据传输速率。
- 易于升级和扩展:QUIC 设计为模块化和可扩展的协议,这使得在不改变底层网络基础设施的情况下,更容易地实现协议升级和添加新功能。
HTTP/3的实现
HTTP/3的实现基于QUIC(Quick UDP Internet Connections),这是一种基于UDP协议的新型传输协议。QUIC是由Google于2012年开始开发的,旨在替代TCP协议,用于提高Web应用程序的性能和安全性。QUIC相比TCP协议,具有以下优势:
- 连接建立速度更快:QUIC会在连接建立时通过加密和认证的方式验证服务器和客户端之间的身份,避免了TLS握手的开销,从而可以更快地建立连接。
- 抗丢包能力更强:QUIC可以在一个连接上并行传输多个数据流,其中一个数据流发生丢包并不会影响其他数据流的传输。
- 降低延迟:QUIC采用了类似于TCP Fast Open的机制,可以在第一次握手时传输数据,从而降低了首次请求的延迟。
HTTP/3基于QUIC实现的主要目的是提高性能和安全性。QUIC协议的特点,如连接建立速度快、抗丢包能力强、降低延迟等,都可以通过HTTP/3来发挥。此外,HTTP/3在数据传输过程中采用了TLS 1.3协议加密数据,更加安全可靠。
在实现上,HTTP/3使用了与HTTP/2相同的API接口,使得应用程序可以在不修改代码的情况下切换到HTTP/3。但由于HTTP/3使用了不同的传输协议,所以底层的实现细节与HTTP/2有所不同。
目前,HTTP/3的实现主要是由谷歌和互联网工程任务组(IETF)推进。IETF于2020年2月宣布QUIC进入正式标准化流程,HTTP/3也在2022年6月6号正式标准化。
HTTP/3 与 HTTP/2 的比较
- 底层传输协议
HTTP/2 依赖于 TCP 作为底层传输协议,而 HTTP/3 则选择了基于 UDP 的 QUIC 协议。这使得 HTTP/3 具有更低的延迟和更好的拥塞控制能力,尤其是在不稳定的网络环境中。
- 多路复用
HTTP/2 和 HTTP/3 都支持多路复用,即允许在单个连接中同时传输多个请求和响应。然而,它们实现多路复用的方式有所不同。HTTP/2 使用基于帧的流来分隔不同的请求和响应,而 QUIC 使用完全独立的流。这使得 HTTP/3 能够避免队头阻塞问题,提高传输效率。
- 连接建立
HTTP/2 依赖于 TCP 的三次握手来建立连接,并在使用 TLS 时需要额外的往返。相比之下,QUIC 支持零往返时间(0-RTT)连接建立,可以显著降低连接建立所需的时间。
- 加密
HTTP/2 通过单独的 TLS 层来实现加密,而 HTTP/3 的 QUIC 协议将加密作为其核心功能,不再依赖单独的 TLS 层。这不仅可以提高安全性,而且可以简化协议栈,提高传输性能。
- 拥塞控制策略
HTTP/2 依赖于 TCP 的拥塞控制策略,而 HTTP/3 的 QUIC 协议实现了更先进的拥塞控制算法,能够更好地应对网络拥塞,提高数据传输速率。
以下是专业人士做的HTTP/2 和 HTTP/3 的单次请求性能对比:
|
小网站 |
内容网站 |
单页面网站 |
HTTP/2 |
500ms |
1000ms |
600ms |
HTTP/3 |
100ms |
675ms |
300ms |
不过想用上HTTP/3还需要很长的时间,毕竟现在HTTP/2也还未全部推广。
标签:协议,UDP,HTTP,TCP,连接,http3.0,QUIC,比较,http2.0 From: https://www.cnblogs.com/ben7980/p/17278721.html