怎么看HTTP/3

道锋潜鳞
2020-04-01 / 0 评论 / 49 阅读 / 正在检测是否收录...

互联网通信发展史其实是人类与RTT斗争的历史

什么是RTT?

RTTRound Trip Time的缩写,通俗地说,就是通信一来一回的时间。

TCP建立连接时间

最早大家使用TCP来运输HTTP,TCP想必大家很熟悉了,需要三次握手,建立了TCP虚拟通道,那么这三次握手需要几个RTT时间呢?

一去 (SYN)

二回 (SYN+ACK)

三去 (ACK)

相当于一个半来回,故TCP连接的时间 = 1.5 RTT 。

HTTP交易时间

这意味着,用户在浏览器里输入的网址URL,直到时间流逝了1.5RTT之后,TCP才开始运输HTTP Request,浏览器收到服务器的HTTP Response,又要等待的时间为:

一去(HTTP Request)

二回 (HTTP Responses)

故HTTP的交易时间 = 1 RTT

那么基于TCP传输的HTTP通信,一共花费的时间总和:

HTTP通信时间总和 = TCP连接时间 + HTTP交易时间= 1.5 RTT + 1 RTT = 2.5 RTT

安全加密通信

随着互联网的爆发式增长,人类发现完全明文传输的HTTP通信很不安全。做为OSI七层参考模型的现实实现的TCP/IP协议,在设计之初没有考虑安全加密的环节。

互联网先驱Netscape公司,创造性发明了SSL(Secure Socket Layer),SSL位于TCP与HTTP之间,做为HTTP的安全供应商,全权负责HTTP的安全加密工作。

IP / TCP / SSL / [HTTP]

各个通信模块之间的站位如上所示,将HTTP用[ ]括起来,表示HTTP被SSL安全加密了。

随着SSL的名气攀升,互联网标准化组织IETF,觉得SSL是一个好东西,就拿来用了。

但SSL最初只是用于加密HTTP的,IETF觉得这是一个硬伤,为什么不能用来做为所有应用层协议的安全供应商呢?来传输邮件、文件、新闻等等。实现这一点很简单,只要在协议里增加一个Application Protocol 类型字段。

在Application Protocol 有一个类型是“IP”,意味着TLS不仅可以运输应用层协议如HTTP、FTP,还可以运输IP,这就是Cisco Any Connect的应用场景。

TLS (Transport Layer Security)

于是,IETF在SSL 3.0版本的基础上,重新设计并命名了这个协议,其全新的名字为TLS,最初的版本为1.0版本。从其名字就可以看出,其核心使命就是保证传输层的安全。各个通信部门成员的占位与SSL占位一致:

IP / TCP / TLS / [HTTP]

到目前为止,浏览器支持的TLS版本为TLS 1.0、1.1、1.2,当然版本越高越成熟、越安全。

HTTPS

通常将TLS安全保护的HTTP通信,称之为HTTPS,以区别于没有TLS安全防护的HTTP明文通信。

交待了上文的背景知识,还是要回到本文的主题,来看看自从引入了TLS安全防护,看看HTTPS通信的RTT增加到了多少?

TLS 1.2

以1.2 版本为例,看看HTTPS通信一共要消耗几个RTT时间?

1. 浏览器给服务器发送的Client Hello消息(一去)

首长好,我支持1.2版本,加密套件列表1、2、3…,以及我的随机码N1,请出示您的证件。

2. 服务器给浏览器发送的Server Hello消息(二回)

同志们好,那就1.2版本通信吧,加密套件我选用1,我的随机码N2,ECDHE密钥交换素材2,这是我的证件。同志们辛苦了!

3. 浏览器给服务器发送的Key Exchange消息(三去)

为人民服务! 嘴里虽这么说着,私下还要偷偷验证首长的证件是否伪造的。

首长证书验证成功之后,还要给首长会话呢?会话内容如下:首长辛苦了! 我的ECDHE密钥交换素材1,接下来我发给您的消息都要加密了(Change Spec)。

从这以后,双方的HTTP通信将使用TLS加密了。一共花费了1.5个RTT时间。

让我们来计算一下整个HTTPS通信花费的时间总和:

HTTPS通信时间总和 = TCP连接时间 + TLS 连接时间 + HTTP交易时间= 1.5 RTT + 1.5 RTT + 1 RTT = 4 RTT

如果浏览器与服务器物理距离很近,RTT < 10 ms,即使4 RTT最大也不过40 ms的时间,用户压根感觉不到慢。

如果浏览器与服务器相隔上万公里,一个RTT时间通常在200ms以上,4RTT时间通常在1秒以上,用户会明显感觉到网速慢了。

HTTP 1.x

和很多人想象不一样的是,浏览器从服务器获取的一个页面,

通常由很多资源链接所组成。

服务器给浏览器推送的第一个页面,页面里通常嵌入了图片资源文本链接、以及动态页面资源链接、或第三方网站的链接资源,还需要浏览器根据这些文本链接内容,去链接所对应的服务器,继续下载链接所对应的内容。浏览器通常采用的流程是,重新建立一个TCP连接、TLS连接、HTTP交易。

这又是一个漫长的4RTT等待过程,用户看到浏览器完整页面的时间为

完整页面加载时间 = 4RTT *2 = 8RTT

HTTP /2

自然有人会问,既然第一次页面与第二次页面都是同一个网站服务器,为何第二次页面要重新建立一个TCP连接,一个TLS连接?

如果重用第一个TCP连接,那么就少了1.5 RTT + 1.5 RTT = 3 RTT的时间。

这是一个好主意,就是用户的多个HTTP Request请求,使用同一个逻辑通道进行运输,这样会大大减少重新建立连接所花费的时间。

但是,这样会带来一个副作用,多个HTTP流使用同一个TCP连接,遵守同一个流量状态控制。只要第一个HTTP流遭遇到拥塞,剩下的HTTP流压根没法发出去,这就是头部阻塞(Head of line Blocking)。既然TCP不好用,那为何要吊死在TCP这一棵树上呢?

外面的世界很精彩,到外面的世界逛逛。

QUIC(Quick UDP Internet Connection)

逛下来的感受是,UDP不需要连接,不会带来附加的RTT时间,UDP是一个好的合伙人被HTTP /2拉上了贼船,各合伙人的站位如下:

IP / UDP / QUIC

这个就是Google开发QUIC协议,QUIC协议集成了TCP可靠传输机制、TLS安全加密、HTTP /2 流量复用技术,其页面的加载时间为2.5 RTT时间。

此外,完成QUIC交易的连接的Session ID会缓存在浏览器内存里,如果用户再次打开该页面,无需建立TLS连接,直接使用缓存Session ID 对应的加密参数,服务器可以根据Session ID在缓存里查找对应的加密参数,并完成加密。

换句话说,重连TLS连接是一个0 RTT 事件,用户所要等待的页面加载事件 =HTTP交易事件 = 1 RTT。

HTTP /3

这一次IETF又觉得QUIC是一个好东西,但是希望QUIC不仅可以运输HTTP,还可以运输其它协议,把QUIC与HTTP分离,最终各合伙人的占位如下所示:

IP / UDP / QUIC / HTTP

这样整体的页面加载时间为2 RTT。

TLS 1.3

IETF的QUIC标准集成了TLS 1.3版本,1.3版本更简练,建立TLS连接不再需要1.5 RTT,而只需要1 RTT,是因为浏览器第一次就把自己的密钥交换的素材发给服务器,这样就节省了第三次消息,少了0.5个RTT时间。

页面的整体加载时间 = TLS 1.3连接时间 + HTTP交易时间 = 1RTT + 1RTT = 2 RTT

重连页面的加载时间 = HTTP交易时间 = 1 RTT

HTTP /3所带来的挑战

99%+以上的手机移动终端、电脑终端,都使用私有IP,都需要NAT设备来完成私有IP与全球IP的转换。这意味着NAT设备通常会记忆用户的通信状态,一旦用户完成了通信,NAT设备会释放这些记忆

对于基于TCP的HTTP、HTTPS传输,NAT设备可以根据TCP报文头的SYN / FIN状态位,知道通信什么时候开始,什么时候结束,对应记忆的开始、记忆的结束。

但是基于UDP传输的HTTP/3,NAT设备收到流量会知道连接什么时候开始,但是却无法知道流量什么时候结束。

NAT设备的记忆如果短于用户会话时间,则用户会话会中断。

NAT设备的记忆如果大大长于用户会话时间,则意味着NAT设备的端口资源会白白被占用!

最直接的解决方案是,在QUIC的头部模仿TCP的SYN/FIN状态,让沿途的NAT设备知道会话什么时候开始、什么时候结束。但这需要升级全球所有的NAT设备的软件!

另外一个可行的方案是,让QUIC周期性地发送Keepalive消息,刷新NAT设备的记忆,避免NAT设备释放自己的记忆。

HTTP/3 或者说核心的 QUIC 协议主要是在做三个事情:

  1. 通过提高链接利用效率减少 RTT,提高数据交互速度。
  2. 在第一条的基础上,囊括安全需求。
  3. 解决当前实际网络环境中的适配问题,也就是说协议不能太过 Breaking Change 了。

HTTP/1.1 持续发展中,有两个东西变得比较重要,一个是 HTTPS,一个是 HTTP/2。

其中, HTTPS 是在 HTTP 的协议上加了一层加密协商,这层加密协商在提高安全性的同时带来了完全新增的 TLS RTT,这对延迟是必然的增加。HTTP/2 的链接复用虽然可以将多个资源放到一个链接里,实现多路复用,却仍有 TCP 层面的排头阻塞(Head-of-line blocking)问题。

QUIC 要解决上面问题,要安全,也要复用。会话层是不能单独拿出来做协商了,这个 RTT 是不能留的,最好就是把他整合到新的协议里,所以 QUIC 是 Build-in security; HTTP/2 的复用能力更要覆盖,所以 QUIC 链接建立后的 HTTP 请求也是能直接复用的,等于是完成上述两个东西的一个优化协议。

然而,QUIC 的实现在传输层换了协议,从 TCP 换到了 UDP,这个变化可不是说升级就升级的,因为 QUIC 协议要保证可靠、有序、能校错,这些都不是 UDP 被对待的方式啊!很多场景下,UDP 都被当做「可以偶尔被丢弃的流量」,这对一个可靠数据传输是不能承受的。

比如,一个官方的例子:NAT 网关。NAT 网关对 TCP 的映射是根据 source_ip:port 和 destination_ip:port 来做的,经过 NAT 网关的 TCP 流量都通过这个四元组做识别,监听 SYN 和 ACK 可以确定 TCP 链接是否建立是否断开;而 NAT 网关对 UDP 流量的处理却没有这么可靠,对于 UDP 流量,NAT 的端口映射可能在某次传输超时之后就被重新分配了,这本来对 UDP 的不可靠的流量也不那么严重,但 QUIC 基于这种实际情况下做,某个建立好要复用的链接,对 NAT 内部机器来说流量来源的端口是会发生变化的,从而四元组做链接标识的事情就结束了。

0

评论 (0)

取消