QUIC 概览
所以,QUIC 与 http3 啥关系呢? QUIC 用来替代 TCP、SSL/TLS 的传输协议,在传输层之上还有应用层,如http、ftp、imap 等,理论上这些协议都能运行在 QUIC 之上。运行在 QUIC 之上的 HTTP 协议被称为 https 。 QUIC的几个重要特性如下面介绍:
1、只要1个RTT建立连接
Http2 基于TLS首次建立连接需要 3 个RTT,而 http3 首次建立连接只需要 1 RTT,首次连接后,后续连接只需要 0 RTT。如图:
那么,http3 如何做到,且看连接过程:
- 首次连接时,客户端发送 Inchoate Client Hello 给服务端。
- 服务端生成 g、p、a,再根据 g、p、a 算出 A,然后将 g、p、A 放到 Server Config 中再发送 Rejection 消息给客户端。
- 客户端接收到 g、p、A 后,再自己生成 b ,根据 g、p、b 计算出 B,根据 A、p、b 算出初始秘钥 K ,B 和 K 计算好之后,客户端用 K 加密 http 数据,连同 B 一起发送给服务端
- 服务端收到 B 后,根据 a、p、B 生成与客户端相同的秘钥,再用这个秘钥解密收到的 http 数据。为了前向安全,服务端会更新自己的随机数 a 和 公钥,再生成新的密钥 S,然后把公钥、Http 返回的数据通过 Server Hello 发送给客户
- 客户端收到 Server Hello 后,生成与服务端一致的新秘钥 S ,后面的传输都用 S 加密。
2、连接迁移(QUIC连接不受四元组影响)
QUIC 连接不受四元组(源IP、源端口、目的IP、目的端口)影响,道理很简单:QUIC 不以四元组作为标识,而是使用一个 64 位的随机数,即使 IP 或者端口变化,称之为 Connection ID ,只要 这个 Connection ID 没变化,那么连接依然可以维持连接。
而使用TCP的话,切换网络时至少会有一个因素发生变化,当连接发生变化时,如果还使用原来的TCP连接,则会导致连接失败,就得等原来的连接超时后重新建立连接,所以,我们有时候发现切换到一个新网络时,即使新网络很好,但内容还是要加载很久。如果实现得好,当检测到网络变化时立刻建立新TCP连接,但这样建立连接还是需要好几百毫秒。
3、队头阻塞/多路复用
TCP 是个面向连接的协议,即发送请求后需要收到 ACK 消息,如果每次请求都要收到上次请求的 ACK 消息后再请求,无疑效率很低。
后来http1.1 做了改进,允许一个TCP连接同时发送多个请求,在这个背景下,谈谈http1.1的队头阻塞:一个TCP连接同时传输了 10 个请求,其中 1、2、3个请求已经被客户端接收,但是第 4 个请求丢失,那么后面第 5~10 个请求都被阻塞,需要等第 4 个请求处理完毕才能被处理,这样就浪费了带宽。因此,http一般又允许 6 个TCP 连接,这样可以更加充分利用 带宽,但是每个连接中队头阻塞的问题还是存在。
http2 的多路复用解决了 http1.x 中的队头阻塞问题,它不用等上一个请求的所有数据包传输完毕之后才能下一个请求,http2每个请求被拆分多个 Fragme 通过一条 TCP 连接同时被传输,这样即使一个请求被阻塞,也不影响其他请求,如下所示:
由于http2 还是基于 TCP 的,虽然在上述粒度上已经解决队头阻塞,但TCP 处理数据时有严格的前后顺序,先发送的 Frame 要先被处理,这样,即使发送了 4 个请求,1,3,4 都已经到达,但是只能先处理了 1, 而 3 、 4 到了也不能被处理,这时候整条连接都被阻塞,如图所示:
不仅如此,http2基于TLS ,TLS协议也存在队头阻塞问题,因为TLS 也是基于 TCP ,它将一堆数据加密,加密完成后又拆分成多个 TCP 包传输,丢了任何一个都不能解密。
那 QUIC 是如何解决的呢?有2点:
- QUIC 的传输单元是 Packet,加密单元也是 Packet ,整个加密、传输、解密都是基于 Packet,这样就能避免 TLS 的队头阻塞
- QUIC 基于 UDP,UDP 的数据包在接收端没有处理顺序,即使中间丢失了包,也不会阻塞整条连接。
拥塞控制
TCP 的拥塞控制就3个方法: 慢启动、拥塞避免、快速恢复 (博客中应该写错了)
QUIC 可以在应用层修改 拥塞控制策略;而TCP 要修改的话,只能在系统层面,
流量控制
TCP 会对每个TCP 连接进行流量控制,意思是让对方不要发送太快,TCP 主要通过 滑动窗口 来实现这个功能。
QUIC 只需要建立一条连接,这条连接同时传输多条 Stream ,好比一条路,两头分别有仓库,道路中间很多车辆运送物资。QUIC 流量控制有两个级别: 连接级别 和 Stream 级别。就好比纪要控制这条路的总流量,不要一下子很多车辆涌进来,货物来不及处理,也不能一辆车一下子运送很多东西,这样货物也来不及处理。那到底怎么实现呢?它的实现也与滑动窗口类似,接收方会发送 WINDOW_UPDATE frame 告诉发送方你可以再多发送些数据过来。
以上内容参考腾讯技术团队的博客