HTTP3
# Http2 的缺点
# 建立连接的延迟
- TLS建立减速
HTTP/2需要在建立连接之后进行TLS握手,而TLS握手需要进行公钥加密、私钥解密等过程,导致了连接建立的延迟。尽管HTTP/2通过TLS协议保证了数据的安全性,但是这种延迟在一些场景下可能会影响性能。
在进行连接的建立时,会先进性tcp的三次握手,在进行在tcp协议上层的TLS四次握手(位于传输层和应用层之间)。
- TCP特性减速
另外,TCP 由于具有「拥塞控制」的特性,所以刚建立连接的 TCP 会有个「慢启动」的过程,它会对 TCP 连接产生“减速”效果。
# 队头阻塞
产生对象:
概念:在网络传输中,由于数据包必须按照顺序传输,因此如果某个数据包丢失或者延迟,后续的所有数据包都必须等待这个数据包传输完成后才能继续传输,这就导致了队头阻塞的问题。
举例:
例如,考虑一个基于TCP协议的数据传输场景。假设一个发送方发送了多个数据包给接收方,这些数据包的顺序如下:A、B、C、D、E、F。接收方会按照顺序接收这些数据包,并且发送确认信息给发送方,表示已经成功接收到这些数据包。但是如果数据包B在传输过程中丢失或者延迟,那么接收方将无法接收到数据包B,并且也无法确认数据包B已经成功接收。这样,发送方将无法继续发送数据包C、D、E、F,直到接收方重新确认接收到了数据包B。这就导致了队头阻塞的问题。
对于http2来说:
在HTTP/2协议中,请求和响应的头信息(Header)都被封装到了一个二进制帧(Frame)中,并且这些帧必须按照顺序传输。如果一个帧在传输过程中发生了丢失或者延迟,那么后面的所有帧都需要等待这个帧传输完成后才能继续传输,这就导致了头阻塞的问题。由于HTTP/2协议使用了一个TCP连接来传输所有请求和响应数据,因此头阻塞也间接导致了TCP连接的队头阻塞问题。
从上面的描述其实我们可以看出来,每一个http2请求响应报文都会在应用层被拆分为二进制帧传输,每个帧携带着部分数据。这些帧被封装在HTTP/2的数据流(Stream)中,每个数据流都有唯一的标识符,称为流ID。每个数据流中的帧可以并行传输,并且可以根据帧的优先级进行流量控制。
HTTP/2协议的二进制帧可以携带各种类型的数据,例如请求头、请求体、响应头、响应体等。在传输过程中,HTTP/2协议会对帧进行压缩、排序和解析,以保证帧的正确性和有序性。而应用层的HTTP请求和响应数据则是被拆分成帧的最小单位,每个帧都会被封装在HTTP/2的数据流中进行传输。
那么从http2的帧到tcp,会经历哪些呢?
当HTTP/2应用程序发送请求时,请求会被拆分成多个HTTP/2帧,并将这些帧放入一个或多个HTTP/2数据流中,每个数据流都被赋予唯一的流标识符。然后,HTTP/2协议将每个数据流中的帧发送给对应的TCP连接,以便进行传输。
TCP协议是一个可靠的、面向连接的协议,它将HTTP/2帧封装在TCP数据段中进行传输。具体来说,HTTP/2帧通过HTTP/2协议栈发送给TCP协议栈,并由TCP协议栈进行分段和封装。TCP协议栈将HTTP/2帧分成适当大小的TCP数据段,并为每个TCP数据段添加TCP头和TCP尾部,生成TCP数据包。TCP数据包中的TCP头部包含了源端口、目的端口、序号、确认号、标志位等信息,用于保证数据传输的可靠性和有序性。
当TCP数据包到达接收方的TCP协议栈时,TCP协议栈将TCP数据段进行重组,并将完整的HTTP/2帧发送给HTTP/2协议栈进行处理。HTTP/2协议栈对HTTP/2帧进行解析、排序、处理和压缩,然后将HTTP/2应用程序需要的数据提取出来,传递给上层的应用程序进行处理。
总的来说,HTTP/2应用层数据在传输过程中会被拆分成多个HTTP/2帧,并由HTTP/2协议栈封装成TCP数据包进行传输。接收方的TCP协议栈将TCP数据段进行重组,将完整的HTTP/2帧交给HTTP/2协议栈进行处理,并将最终的数据传递给上层的应用程序。
对于tcp来说,是不是也有这种问题呢?其实并不会,因为他已经有解决方法了。
在TCP协议中,尽管也存在数据包的顺序传输问题,但是TCP协议可以通过序列号和确认号来实现数据包的重传和丢失恢复,从而避免了队头阻塞的问题。但是在一些特定的网络环境中,例如高延迟、低带宽的卫星通信网络中,TCP协议也可能出现队头阻塞问题。针对这种情况,一些专门的协议和技术也提供了相应的解决方案,例如TCP加速、帧优先级、拆分数据包、设置窗口大小等。
上面还有一个数据流的概念,这个概念是干什么的呢
在HTTP/2协议中,数据流(Stream)是指在单个TCP连接上的一个双向通信信道,可以承载双方交换的HTTP/2帧,而这些帧可以随时交错发送和接收。
HTTP/2中的每个数据流都有一个唯一的标识符,称为流ID。在同一个连接中,客户端和服务器可以通过多个数据流同时进行双向通信,这种并发的通信方式可以避免HTTP/1.x中的队头阻塞(Head-of-Line Blocking)问题。
HTTP/2的数据流可以使用一种称为流优先级(Stream Priority)的机制来控制传输顺序,流优先级允许客户端或服务器为每个数据流指定优先级,从而控制带宽分配和数据流的相对重要性。
除了优先级,HTTP/2还支持数据流的复用,也就是说,在同一个TCP连接上,多个数据流可以同时进行双向通信,而不需要等待之前的数据流完成,这样可以减少网络延迟和提高网络性能。
从上面的问题可以看出,其实http1中也有队头阻塞的问题,但是为什么http2的队头阻塞问题依然没有解决?
虽然HTTP/2中引入了数据流的概念来避免HTTP/1.x中的队头阻塞问题,但是在实际的网络环境中,HTTP/2还是可能存在队头阻塞的问题。
这是因为HTTP/2中的流控制机制和优先级机制可以控制数据流的传输顺序和速率,但是它们无法控制网络延迟、带宽限制和数据流的大小,这些因素可能导致数据流传输过程中出现队头阻塞。
另外,HTTP/2的头部压缩机制也可能导致队头阻塞问题。在HTTP/2中,所有请求和响应的头部信息都需要经过压缩后再进行传输,这种压缩机制可以减少网络传输的开销,但是在解压头部信息时,如果出现错误或者丢失了数据,就会导致队头阻塞问题的出现。
因此,尽管HTTP/2中引入了数据流的概念来避免HTTP/1.x中的队头阻塞问题,但是在实际的网络环境中,仍需要采取一些措施来避免或者减轻队头阻塞的影响,例如使用合适的流控制和优先级机制,以及控制数据流的大小和频率等。
关于更多http2的帧流问题,可以阅读下面这篇文章 https://www.jianshu.com/p/51b2a9c98fca (opens new window)
https://zhuanlan.zhihu.com/p/330300133 (opens new window)
# 网络迁移需要重新连接
主要会发生在TCP:
一个 TCP 连接是由四元组(源 IP 地址,源端口,目标 IP 地址,目标端口)确定的,这意味着如果 IP 地址或者端口变动了,就会导致需要 TCP 与 TLS 重新握手,这不利于移动设备切换网络的场景,比如 4G 网络环境切换成 WiFi。
在TCP/IP协议中,当进行网络迁移时,由于网络地址的改变,TCP连接会中断,需要重新建立连接以确保数据传输的可靠性。
从上面的http2可以看到:
HPack和Stream都是HTTP/2中的新特性。
HPack是HTTP/2中的头部压缩机制。在HTTP/1.x中,每次请求和响应都需要传输大量的头部信息,这些头部信息会占用大量的带宽。为了解决这个问题,HTTP/2使用HPack对头部信息进行压缩,将多个相同的头部信息压缩为一个共享的索引,从而节省了带宽和传输时间。
Stream是HTTP/2中的一条逻辑通道,用于在单个TCP连接上传输多个并发请求和响应。在HTTP/1.x中,每个请求和响应都需要使用一个新的TCP连接,这会导致连接数的过多,影响网络性能。HTTP/2中使用Stream可以在单个TCP连接上实现多路复用,即可以同时传输多个请求和响应,这极大地提高了Web性能。
通过HPack的头部压缩机制和Stream的多路复用特性,HTTP/2可以更有效地利用带宽,减少延迟,并提高Web性能。
除了上面的特性外,还有以下特性:
- 服务器推送(Server Push):HTTP/2允许服务器在客户端请求之前主动推送一些资源,这些资源可能会被客户端所需的页面所用到,从而加快页面加载速度。
- 二进制分帧(Binary Framing):HTTP/2使用二进制协议对请求和响应数据进行分帧,而不是HTTP/1.x中的文本格式,这样可以更有效地处理数据,减少了传输数据的大小和延迟。
- 流量控制(Flow Control):HTTP/2支持流量控制,可以避免网络拥塞和性能下降,从而提高Web性能。
- 请求优先级(Priority):HTTP/2允许客户端设置请求的优先级,以确保重要的请求可以更快地响应,从而提高Web性能。
- 多域名支持(Multi-Origin Support):HTTP/2允许在一个单一的连接中同时处理多个域名请求,从而可以减少网络延迟和连接数,提高Web性能。
# HTTP3 实现
使用QUIC协议
# 基于UDP协议
UDP 是一个简单、不可靠的传输协议,而且是 UDP 包之间是无序的,也没有依赖关系。
而且,UDP 是不需要连接的,也就不需要握手和挥手的过程,所以天然的就比 TCP 快。
然后在应用层实现了QUIC【Quick UDP Internet Connections】协议
HTTP/3 不仅仅只是简单将传输协议替换成了 UDP,还基于 UDP 协议在「应用层」实现了 QUIC 协议,它具有类似 TCP 的连接管理、拥塞窗口、流量控制的网络特性,相当于将不可靠传输的 UDP 协议变成“可靠”的了,所以不用担心数据包丢失的问题。
QUIC 协议的优点有很多,这里举例几个,比如:
- 无队头阻塞;
- 更快的连接建立;
- 连接迁移;
# 无队头阻塞
QUIC中的无对头阻塞(Head-of-Line Blocking)是指当一个数据包被丢失或延迟时,后续的数据包就会被阻塞,无法被接收和处理,从而导致整个数据流的延迟和性能下降。
为了解决这个问题,QUIC引入了Packet Number和Stream ID的概念。Packet Number用于标识每个数据包的序号,使得接收方可以检测到是否有数据包丢失或重复,并且可以快速重传或丢弃这些数据包。Stream ID用于标识每个数据流,使得接收方可以根据需要调整数据流的优先级和顺序,从而避免阻塞。
QUIC 协议也有类似 HTTP/2 Stream 与多路复用的概念,也是可以在同一条连接上并发传输多个 Stream,Stream 可以认为就是一条 HTTP 请求。
由于 QUIC 使用的传输协议是 UDP,UDP 不关心数据包的顺序,如果数据包丢失,UDP 也不关心。
不过 QUIC 协议会保证数据包的可靠性,每个数据包都有一个序号唯一标识。当某个流中的一个数据包丢失了,即使该流的其他数据包到达了,数据也无法被 HTTP/3 读取,直到 QUIC 重传丢失的报文,数据才会交给 HTTP/3。
而其他流的数据报文只要被完整接收,HTTP/3 就可以读取到数据。这与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。
所以,QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其他流不受影响。
解释一下上面的重点:
这句话的意思是,在HTTP/3中,如果某个流(stream)中的数据包丢失了,不会影响其他流的数据报文。只要其他流的数据报文被完整地接收,HTTP/3就可以读取这些数据。换句话说,HTTP/3使用了更加健壮的协议来保证数据的可靠性和完整性。
而在HTTP/2中,如果某个流中的数据包丢失了,其他流也会因此受到影响。因为HTTP/2使用了复用连接(multiplexing)的技术,多个流可以共享一个连接。这种情况下,如果某个流中的数据包丢失了,会导致整个连接的拥塞控制机制启动,从而影响其他流的数据传输。
因此,HTTP/3比HTTP/2更加健壮,可以更好地保证数据传输的可靠性和完整性。
2
3
4
5
从知乎上面看到的一张图
通过TCP-》UDP的转换,其实可以看到解决队头阻塞的关键点:给传输的包进行编号
为什么给数据包编上序号就可以解决问题了,之前没有序号为什么会出现队头阻塞问题?
在没有数据包序号的情况下,如果有一个数据包在传输过程中出现丢失或延迟,那么接收方就无法知道下一个期望接收的数据包是哪一个,因为没有办法判断数据包的顺序。这时候,接收方只能等待丢失或延迟的数据包重新传输过来,才能继续接收后续的数据包。
由于数据包的传输是有序的,即后面的数据包必须等待前面的数据包传输完毕才能进行传输,因此前面的数据包的延迟或丢失就会导致后续数据包被阻塞,无法及时传输。这就是所谓的“队头阻塞”(Head-of-Line Blocking)问题。
通过给数据包编上序号,接收方就可以根据序号来判断数据包的顺序,并且可以检测到是否有数据包丢失或重复。这样一来,即使有数据包出现延迟或丢失,接收方仍然可以知道下一个期望接收的数据包是哪一个,并且可以继续接收后续的数据包。同时,接收方还可以快速重传或丢弃丢失或重复的数据包,从而避免了队头阻塞问题的发生。
# 更快的连接建立
1.0-RTT 握手:QUIC 协议支持 0-RTT 和 1-RTT 两种握手方式,其中 1-RTT 握手可以在建立连接的第一个往返时延(Round Trip Time,RTT)内完成,比传统的 TCP + TLS 握手时间更短。
2.无需等待 TCP 连接建立:HTTP/3 在 QUIC 协议之上实现,QUIC 协议不需要等待 TCP 连接建立,从而可以节省连接建立的时间。
3.快速恢复:当连接遇到丢包等问题时,QUIC 协议支持快速恢复(Fast Retransmit)和快速重传(Fast Recovery)机制,可以减少连接恢复所需的时间,从而减少了整个连接的建立时间。
4.多路复用:HTTP/3 支持多路复用,即可以在同一连接上传输多个请求和响应,从而避免了建立多个连接的开销,提高了连接的利用率。
综上,HTTP/3 通过 QUIC 协议实现了更快的连接建立,其中 1-RTT 握手、无需等待 TCP 连接建立、快速恢复、多路复用等机制都为连接建立提供了加速的手段。
对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、OpenSSL 库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手,再 TLS 握手。
HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。
但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是 QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS 1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。
如下图右边部分,HTTP/3 当会话恢复时,有效负载数据与第一个数据包一起发送,可以做到 0-RTT:
# 网络迁移不回造成重新连接
在 HTTP/3 中,由于使用了基于 QUIC 协议的传输层,因此网络迁移(比如从 Wi-Fi 切换到移动数据网络)不会导致连接中断。
QUIC 协议中使用了连接 ID 和版本号来识别连接,这些信息与底层网络细节无关。在网络迁移时,QUIC 可以在新网络上重新建立连接,而不会中断现有的连接。同时,QUIC 协议使用了类似于 TCP 的拥塞控制算法来控制数据传输速度,可以在网络状况变化时及时地适应新的网络条件,从而保证连接的稳定性和可靠性。
因此,HTTP/3 中的网络迁移不会中断连接,同时也不会对传输的数据产生影响,保证了连接的连续性和可靠性。
# HTTP3的帧结构变化
HPack与QPack的变化