HTTP协议的理想性能

原文: https://www.mnot.net/blog/2016/04/22/ideal-http

 

提高WEB服务的性能的目标就是减少用户到服务端的时延,减少用户等待的时间,把页面以最快的速度呈现给用户。

以下是一个理想的HTTP协议交互的过程:

如上图所示,一个比较理想的页面加载过程需要达到以下三个标准:

1) 客户端发送尽量少的数据给服务端;

2) 客户端尽量少的从服务端下载数据;

3) 以及最少的往返次数

额外的数据传输不仅会消耗更多的时间,还可能导致网络拥塞,丢包,验证的影响性能。按照上边的三个标准,HTTP服务该如何进行优化呢?

 

HTTP/1.1

HTTP1.1是一个非常优秀的协议,但是从现代的web的使用方式来看,http1.1的性能是明显不够的,一般的页面加载过程大致是如下这样的:

 

上图的http1.1的交互过程看起来并不是很理想的

客户端需要请求服务器多次才能获取到html文档,以及其他的图片资源。先需要获取html,接着CSS和JS。这个过程中的每一次的数据交互,都会增加一个数据传输的往返时延,有可能会更多。这违背了上面我们说的第三条标准“ 尽量少的往返次数”;

此外,为了完成一次数据的请求,我们还需要增加传输一些其他的数据。这也违背了上面说的第一条标准" 客户端发送尽量少的数据给服务端”。那为什么需要添加一些其他的数据呢? 这是因为在每一个HTTP请求过程中需要添加一些如:Referer,User-Agent,Cookie的http的头部信息。并且http1.1存在着对头阻塞的问题,在实际的应用中,通常我们会把众多的资源和串联整合到css spriting,使用内联或者串联等。这些技巧在http1.1中表现的非常好。但同时也是有代价的。这样会使得用户不得不下载更多的数据。这也违背我们“下载尽量少的数据”的原则。这就意味着我们并没有那么理想的以最快的速度把网页呈现给用户。

总的来说,http1.1也不是一无是处的,在性能表现上还是可圈可点的。比如它的缓存机制,就有效的避免了客户端下载本地已有数据副本的数据。还有“条件请求”(包括 If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, If-Range等头部) 避免了在缓存中的数据副本过期的时候传输大量的数据。

 

HTTP/2

http/2试图从以下的几个方面来解决http1.1中的问题

  1. 完整的多路复用技术:多路复用技术下,用户只需要通过一个http连接就可以完成整个WEB页面的加载,头部阻塞将不会再成为问题,并且也不需要担心会出现雨多多余的请求。那么关于如何减少多余数据发送的一些优化也就先放一放了;

  2. 头部压缩:头部压缩解决了冗余头部带来的资源浪费,现在你完全可以只使用几个IP数据包就可以几十个,甚至是上百个请求。越来越接近“最小数据量”的理想目标了;

  3. 服务端推送:http/2允许服务端预测客户端可能需要什么资源,并将这些资源主动的推送到客户端,省去了多余的数据请求。

因此,一个http/2的交互大概是以下这样的:

如上图所示,服务端发送CSS,JS,图片给客户端的时候,客户端并没有主动请求这些资源。因为它知道客户端在请求html资源之后需要请求这些资源,所以直接推送数据到客户端,可以较少一次网络的往返。

但这些也不是完全理想,没有任何问题的。还有很多HTTP/2公认的问题,比如服务端推送。接下来我们单独讨论:

 

HTTP/2 + 缓存摘要

关于服务器推送的一个常见问题是:“如果客户端已经有了缓存数据,怎么办?”因为默认推送,服务器就可能发送给客户端它并不需要的东西。

http/2使用RESET_STREAM的机制允许客户端取消服务器的推送来解决这个问题。尽管如此,还是多了一次的传输往返。请记住,我们的理想状态是只发送给客户端它需要的东西的。

一个解决方案是利用缓存摘要的方式让服务器知道客户端已经有了数据的副本。

因为缓存摘要使用的是Golumb压缩集合,所以客户端只需要不到一千个字节就可以告诉服务器自己已经有了资源的副本。这样我们就避免了额外的往返、数据并联和串联的浪费了,也就离我们理想的状态又进了一步了。

 

TCP

截止目前,我还没有谈到浏览器使用的其他协议对性能产生的影响。

然而,在之前的很多图片都已经向大家展示了,在HTTP开始之前,客户端和服务端必须通过三次的TCP握手。详细的交互和协商过程如下图:

这就意味着每一次请求都增加了一个完整的往返。

TCP Fast Open:TFO允许应用在SYN和SYN-ACK的保重携带数据来避免这个问题。但是,当前这种机制还只支持Linux和OSX。此外,在HTTP中使用TFO仍然有一些问题,社区也在着手解决。

TFO无法保证SYN上发送的数据只发送一次,很容易被复制和被攻击。所以,对于第一个是POST的HTTP请求,是不建议使用TFO的。更让人头疼的是,一些GET请求也同样存在问题,并且浏览器并没有好的方案来检测哪些URL需要如此。

 

TLS

在tcp的握手完成之后,如果开启了ssl,那么就需要进行另一次的TLS的握手:

在这种情况下HTTP的请求发送之前,还需要进行两次完整往返的TLS握手。当然,如果客户端和服务端之前已经建立过TLS连接,那么 session tickets可以减少其中的一次往返。

在TLS1.3中,如果客户端和服务端之前建立过TLS连接,TLS1.3将可以做到“0往返”捂手。HTTP请求在第一个往返的时候就可以直接发送数据了,避免其他任何往返的时延。当然,像TFO那样,你需要保证在第一次往返中产生的重复数据不会中断其他任何事情。

 

下一代的HTTP协议

TFO和TLS1.3都是为了减少客户端到服务端建立新的请求。另一种方案是尽可能的重用已经打开的连接。

为此,我们正在积极的讨论如何更好的利用HTTP2的连接复用功能。它不仅有助于避免打开新连接的开销,而且还使现有连接更有效,因为TCP最适合长时间使用的繁忙数据流场景。

同时也包含了如推送证书到客户端,以使连接在最初的协商阶段就可以被更多的终端所使用。

一些更为激进的方案如使用UDP来替代TCP,如:QUIC也在深入的讨论中。过度到quic还需要很长的路要走,但是从性能上来考虑,能在不改变客户端操作系统的情况下,在第一次的往返过程中就完成握手还是非常吸引人的。此外,能够无序的访问缓冲区中的数据,这就意味着TCP中的首部阻塞将不再是一个问题了。您可以在丢弃的包的后面继续选择HTTP消息或者其他部分,一遍更快的将它们呈现给用户。

QUIC还处于早期阶段,因此我们可能暂时看不到基于uddi的HTTP标准化和广泛部署——甚至可能看不到。但是我们可以从 QUIC 中来认识我们想要 TCP 如何更加高效,使 Web 服务获取到更高的性能。在一个复杂的互联网上,这种可能性有多大还有待观察。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值