-

Quic 全称 quick udp internet connection,“快速 UDP 互联网连接”,(和英文 quick 谐音,简称“快”)是由 google 提出的使用 udp 进行多路并发传输的协议。

2018 年,互联网标准化组织 IETF 提议将“HTTP over QUIC”更名为“HTTP/3”并获得批准,HTTP/3 。

Quic 相比现在广泛应用的 http2+tcp+tls 协议有如下优势:

  1. 减少了 TCP 三次握手及 TLS 握手时间。
  2. 改进的拥塞控制。
  3. 避免队头阻塞的多路复用。
  4. 连接迁移。
  5. 前向冗余纠错。

我们知道,UDP速度足够快,但不够可靠;TCP足够可靠,但三次握手确认逻辑会使得网络连接不够快。

那么这时我们会产生四个问题:

  1. 传统的TCP/IP协议存在什么问题?为什么Http2还未落定就开始推QUIC?
  2. QUIC为什么不在网络栈中单独发明一个协议,而是要基于UDP去做?
  3. 基于UDP的QUIC是安全可靠的吗?怎么做到的呢?
  4. 业内QUIC的使用情况如何?以及面临哪些挑战?

一、传统的TCP/IP协议存在什么问题?

为什么Http2还未落定就开始推QUIC?

发展 TCP 当时的场景和现在主流场景不同,TCP诞生背景是需要保证可靠性、拥塞控制。

现在互联网+的场景比如直播,对于时延的要求性是很高的,但TCP对时间的追求没有那么苛刻。

“TCP+TLS”握手一共需要在客户端和服务端进行4个来回,一共需要4个RTT(RTT:数据发送完到收到确认信号的时间)。

附:一个RTT的时间可以使用 ping 命令进行估算,比如我们打开终端执行如下命令:

ping www.baidu.com

RTT约为70ms,4个RTT即280ms。

TCP连接建立后,从启动到满带宽传输有一个慢启动的过程,传输多个文件就要建立多个TCP连接,慢启动会影响上传速度。

HTTP 1.1 时提出了复用连接的概念,比如如果我们要传两个文件:

  • index.html
  • index.js

当传index.html TCP没有中断时,我再传输 index.js 可以复用传输 index.html 时建立的TCP连接。

但这还是存在一个问题:传输多个文件均是串行传输

再 HTTP2 为了解决串行传输的问题,提出了多路复用的概念,多路复用允许同时去传输两个文件,可以并行去发送 index.htmlindex.js,但同时又带来了TCP队头阻塞的问题。

所以可以这么理解:TCP诞生在网络基建不那么完善的现实背景下,通过网络协议实现了可靠传输,但TCP设计非常容易导致在弱网环境下表现不好。

当前网络基建相对完善,从硬件水平上可以大概率保证网络传输不丢包,那么网络协议该如何与时俱进呢?实现既高效、有尽可能可靠呢?

二、QUIC为什么要基于UDP去做?

QUIC为什么不在网络栈中单独发明一个协议,而是要基于UDP去做?

主要有两点原因:

  • 设计一个轮子比较难,花费时间
  • 传输层协议都是写在操作系统内核中的,修改操作系统内核并部署到所有电脑里,是个工程量非常大的事情

基于上面两点原因,QUIC属于应用层的产物,而非传输层。

三、基于UDP的QUIC是安全可靠的吗?

怎么做到的呢?

Google 的 QUIC 是一种基于 UDP 的低延迟互联网传输协议,该协议常用于游戏、流媒体和 VoIP 服务。

IP和UDP均没有做可靠保证,所以UDP层相当于什么都没有做,只是把数据透传到QUIC的应用层。

但是难道说基于UDP的QUIC就是不可靠的吗?其实不是。

我们从上面的图中罗列一下 QUIC 做了哪些事情:

  • Congestion control Loss recovery:恢复丢失的包
  • TLS
  • Multistreaming:多路复用

可以看到左边TCP做的事情,QUIC也都进行了实现:

那相比TCP,QUIC有什么优点呢?

(一)通过减少往返次数(RTT),以缩短连接建立时间

QUIC提供了0-RTT和1-RTT的连接建立,这也就是说QUIC在最好的情况下不需要额外的往返时间便可以建立新的连接。

两者中更快的是0-RTT,仅在在两个主机之间建立过连接且缓存了该连接的秘钥时可以使用。

那这时我们可能会有一个疑问,设计TCP的祖师爷肯定也知道 RTT次数 越少,传输越快,那还为什么设计3次握手?

发送端(Client)和接收端(Server)总共发起的 3 次request就叫做 3 次握手。

关于TCP syn的理论相信大家已经很熟了,我这里引用网上的一个段子,来说明TCP为什么是3次握手,而不是2次握手或者4次握手。

三次握手:

1
2
3
4
5
“喂,你听得到吗?”

“我听得到呀,你听得到我吗?”

“我能听到你,今天balabala……”

两次握手:

1
2
3
4
5
6
“喂,你听得到吗……吗……吗?”
“我听得到”
…………
“…………”
…………
“……你妹的”(server发现client占用了通道,但又不发送数据)

那为什么基于UDP的QUIC协议也是可靠的呢?

主要原因是QUIC在应用层处理了类似TCP传包的流程,只是在建立连接时无需再等待多次RTT。

可以这么理解:

TCP时代,网络基建不够优秀,建立连接要相当谨慎,网络通路是有限的资源,在发包阶段就要保证可靠性。
QUIC时代,网络基建相当完善,建立连接不再那么苛刻,可以有效地优化弱网的传输流程。

(二)独立的数据流避免阻塞问题

还是以传输 index.htmlindex.js为例,QUIC协议开辟两条数据流传分别传输这两组数据,不会因为一条链路的阻塞导致整个链路的瘫痪。

四、业内QUIC的使用情况和挑战如何呢?

QUIC面临的挑战:

1
2
3
a. 路由封杀UDP 443端口(这正是QUIC部署的端口)
b. UDP包过多,会被服务商误认为是工具,UDP包被丢弃
c. 无论是路由器还是防火墙幕墙对QUIC都没有做好准备

目前业内腾讯、BIGO、豆瓣、Facebook、快手均已进行QUIC协议的接入,在直播推拉流、视频传输有着显著地收效。

有趣地是因为QUIC本身是应用层的协议,且QUIC协议目前处于草案阶段,所以目前业内接入QUIC时,基本会采用两个做法:

  • 自研QUIC,结合自身业务深度定制,比如腾讯的TQUIC
  • 接入AB test,根据网络环境和使用场景动态切换网络协议

虽然QUIC各个特性看上去很美好,但需要客户端/服务端的网络协议栈都支持QUIC协议。截止目前,除iOS 15 在指定接口NSURLSession 及限制条件前提下,支持了HTTP3,其他系统及主流网络库均不支持QUIC。

思考心得

学完QUIC协议,回想我过去工作中和协议相关的事情,我发现其实本质都是相近的。

比如客户端旧版本不支持的pb,后台新版本下发旧版本也解析不了,无法支持。放在QUIC这类网络协议上就是:如果旧版本浏览器或者操作系统不支持解析协议,发送方单方面是推动不了的,必须 Server 与 Client 达成协议。

又或者客户端会针对不同的业务采取 短轮询、长轮询又或者是长连接的业务逻辑,本质就是根据业务场景选择不同的 C-S 沟通方案,QUIC的诞生也是解决 C-S 的沟通效率等问题。

又比如客户端同步用户信息时,也会遇到网络中丢包、重传等问题,客户端采用的 sequence提升与merge 方案与 TCP保证传输可靠性 方案基本一致。

可以这么说:无论是TCP还是QUIC,从诞生到发展一直是在解决现实问题,可以算是Google的一个业务模块,和我们开发一个和网络优化相关的需求类似。