「开位」你所应该知道的HTTP——优化篇

前言

这是本系列的终章,主要讲解有关HTTP在实践中的优化方案。采用遇到问题、分析问题、解决问题的思路进行叙述。
无特别说明均基于HTTP/1.x(简称H1)进行讨论,后面也会提到HTTP/2.0(简称H2)相关的反模式。css

《你所应该知道的HTTP》系列的其余篇章:web

握手延迟

握手延迟是指开始HTTP通讯以前所花费的时间,这里的影响因素是不少的。
握手延迟主要来自三方面:DNS查询、TCP三次握手和TLS四次握手。
DNS查询也叫域名解析,是域名转换到IP地址的过程,如今基本上都是使用域名进行URI的表示,所以DNS查询是必须的步骤。
HTTP是基于TCP的协议,所以TCP的三次握手也是不可避免的步骤。
TLS四次握手的优化已经在HTTPS篇讲过,故此处再也不重复。
咱们优化的目标就是要尽可能下降握手延迟,可用方案以下:ajax

DNS查询优化

  • 限制不一样域名的数量:
    每个域名,就意味着可能须要一次DNS查询,减小域名数量天然有助于减小查询次数。
  • 使用最近的DNS服务器:
    将物理距离的影响尽可能下降,能够优化DNS服务的建设部署或购买靠谱的第三方服务。
  • 在主体页面HTML中使用DNS预取指令:
    DNS-Prefetching是让具备此属性的域名不须要用户点击连接就在后台解析,待用户真的点击连接,就能够少去DNS查询的步骤,从而提升用户体验。

形如:segmentfault

<link rel="dns-prefetch" href="//ajax.googleapis.com">

优化TCP链接

  • 借助CDN网络尽早响应:
    将物理距离的影响尽可能下降,能够自行建设部署CDN网络或购买靠谱的第三方服务。
  • 使用connection:keep-alive:
    这样能必定程度复用TCP,减小TCP链接的创建。
  • 在主体页面HTML中使用preconnect指令:
    向浏览器提供提示,建议浏览器提早打开与连接网站的链接,以便在跟随连接时能够更快地获取连接内容。但不可滥用,一样会占用浏览器的链接数。

形如:api

<link rel="preconnect" href="//font.example.com" crossorigin>

避免重定向

重定向是须要在创建完TCP链接后,服务器才以301或302的状态码告知客户端,这时候一般须要从新创建TCP链接。
所以最好的解决方案固然是完全不要重定向。固然,非要重定向也能够考虑使用下面两个变通办法。浏览器

  • 利用CDN代替客户端在云端实现重定向;
  • 若是是同一个域名的重定向,使用web服务器的rewrite规则,避免浏览器跳转。

减小请求须要

这是最直接的解决办法,不须要那么多的请求需求,天然就没有延迟。主要思路不外乎合并外联资源,但这要适度,由于若是合并的文件过大,反而会下降了加载速度。缓存

  • CSS Sprites(精灵图):
    即将多张图片合并成一张,本来须要多个请求获取的图片,如今只须要一次请求就能获取到。
  • 内联图片:
    使用data:URL模式,就是把图片编码为字串直接嵌入网页。
  • 合并或内联脚本和样式表:
    减小外联的js和css文件天然会减小请求,但内联有助于缓存,这须要平衡考虑。
  • 缓存:
    参见缓存篇提到的Expires或Cache-Control。

队头阻塞

进阶篇中讲到H1的链接管理模型并未提供机制来同时请求多个资源。也就是说它须要发起请求、等待响应,以后才能发起下一个请求。资源将排队等待一问一答的加载,若是中间出现任何情况,都会致使剩下的工做被阻塞
咱们优化的目标就是要尽可能提升并发,减小队头阻塞的影响,可用方案以下:服务器

域名拆分

现代浏览器为了解决这个问题会对单个域名开启6个左右的链接,经过各个链接分别发送请求。它实现了某种程度上的并行,但每一个链接仍会受到“队头阻塞”的影响。
咱们能够利用这一机制,将资源分布在多个域名下,这样一个域名6个请求,两个域名就能有12个请求。但这里也涉及到增长了dns查询、TCP链接增长的问题,故须要达到一个最佳平衡,不可盲目。
Yahoo研究代表,一个网站使用2个主机名进行资源加载可达到最优。cookie

低效的TCP利用

TCP的设计思路:对假设状况很保守,并可以公平对待同一网络的不一样流量的应用。它的成功并非由于传输速度快,而是由于它是最可靠的协议之一。
TCP的经过慢启动,探索当前链接拥塞窗口的合适大小。即先发送少许数据包,若是接收到响应且无丢包,就在下一次发送多一倍的数据包,直到发包上限。也就是说说TCP的传输速度是逐步加快的,并不能一会儿满速的。网络

拥塞窗口(congestion window)
拥塞窗口是指,在接收方确认数据包以前,发送方能够发出的TCP包的数量。
例如:若是拥塞窗口为1,则发送方发出1个数据包以后,只有接收方确认了那个包,才能发送下一个。

拥塞控制.png

而页面文件数据量原本就不大,创建TCP链接每每还没到最佳速度就结束了,即便多条链接并发也不能保证它们性能最优。
咱们优化的目标就是要尽可能复用TCP链接,可用方案以下:

使用长链接

使用connection:keep-alive是H1仅有的提升TCP使用率的办法。

臃肿的消息首部

H1虽然提供了压缩请求内容(body)的机制,可是消息首部却没法压缩。特别是其中的cookie有时很大,这样就天然增长了每次重复的数据量传输,并且自定义头部的增长,这种状况愈来愈严重。
咱们优化的目标就是要尽可能减小消息首部,可用方案以下:

减小cookie

cookie虽然保存在本地,但每次请求都会被发送到服务器,须要尽可能减少cookie大小。须要较大的信息存储时,能够考虑使用其余客户端的缓存,好比:WebStorage、WebDatabases等。

分离资源域名与ajax域名

资源传输通常都不须要cookie,故能够在这类域名上设置cookie禁用。

受限的优先级设置

H1基本没有关于优先级的设计,单纯由浏览器决定,浏览器的有些解析过程还会阻塞资源的请求。
咱们优化的目标就是使用浏览器的特性手动安排优先级,可用方案以下:

合理安排资源加载

  • JS放HTML文档末尾能够防止阻塞其余资源加载;
  • 若是JS执行顺序可有可无,而且必须在onload事件触发以前执行,能够设置asyn属性;
  • 若是JS执行顺序很重要,而且容许脚本在dom加载完后执行,能够设置defer属性;
  • 对不会影响页面初次渲染的JS脚本,能够在onload事件以后再经过动态新建标签请求加载。

升级到HTTP/2.0

升级到H2能够解决大部分上面提到的有关H1的性能问题,上面提到的“队头阻塞”和“低效的TCP利用”会被H2的多路复用解决,“臃肿的消息首部”会被首部表和首部压缩解决,“受限的优先级设置”会被请求优先级解决。
那前面提到的一些优化方案是否还须要保留呢?答案是否认的,一些优化方案不单没有效果反而会成为反模式,这里须要注意:

反模式:生成精灵图和资源合并/内联

单个文件都是能够被缓存的,合并/内联实际上会失去缓存的特性。在H1的是时代牺牲缓存减小请求数是划算的,但H2时代全部资源均可并发,而且只有一个链接,因此缓存的优点会更大。

反模式:域名拆分

为了增长并发请求数,H1时代会将资源分散到多个域名下,但H2时代只有一个链接,而且均可并行请求,因此多个域名只会增长DNS解析的代价和创建链接的耗时。

反模式:禁用cookie的域名

H1时代一些不须要cookie的资源能够放在禁用cookie的域名下减小请求大小,但H2时代的头部是压缩处理的,因此将资源的域名都与主页面一致反而能够减小DNS解析。

相关文章
相关标签/搜索