对减少HTTP请求的疑问

标签: http | 发表时间:2011-05-24 08:35 | 作者:(author unknown) 硬盘被格
出处:http://www.otakustay.com
Shared by Fenng
一个最基本的问题没有考虑吧?浏览器发起请求难道不消耗时间的?

教条

根据各种Web性能优化手册,“减少HTTP请求”这一条始终被放在显眼的位置,其中就包括著名的YSlowGoogle Page Speed,两者对这一教条的解释分别是:

80% of the end-user response time is spent on the front-end. Most of this time is tied up in downloading all the components in the page: images, stylesheets, scripts, Flash, etc.

YSlow表示,前端的多数时间是用在下载图片、样式表、脚本、Flash等,所以要减少HTTP请求。

RTT is the major contributing factor to latency on "fast" (broadband) connections.

Page Speed则表示,RTT(请求往返时间)是导致连接快不起来的主要原因,所以要减少,即减少HTTP的请求数。

疑惑

很少人会对这2大优化守则产生怀疑,因为它们即真理、即教条、即必须遵守之则,如有违逆,虽远必诛……

但是如果认真地去解读这2条规则,其他他们都表达了一个意思:网络上的往返越多,响应的速度就越慢。

但是他们却忽略了一个很重要的事情,那就是工作总用时多,并不代表任务完成时间也多,因为这里有一个概念,叫作并行

试想一个任务,用一个线程跑,和用100个线程跑,哪一个总用时更少?答案其实是一个线程,因为100个线程之间有线程切换的开销、有结果join的时间、有任务分割的时间……但是从结论上来看,哪一个能更快地跑完任务?答案是多线程,这就是并行计算的理论来源。

事实上,资源的下载也是如此,如果并行的话,多个资源的下载时间不见得会小于一个资源,如下图是一个合并后的资源的下载示意:

大资源下载示意

上图用来表示一个较大的资源的下载过程,其中不同的颜色分别对应:

  • 蓝色:TCP链接建立时间
  • 绿色:请求头发送时间
  • 紫色:服务器处理时间
  • 橙色:响应头发送时间
  • 红色:文件传输时间
  • 灰色:文件解析执行时间

如果将这个大资源分解成3个相等的小资源的话,那么他们的下载就可能是这样的:

小资源下载示意

由于浏览器只有一个线程可以对文件进行解析和执行,因此灰色的解析部分必定是串行的,需要相互等待。

比较2张图,假设其中的每一小块的时间为t,可以发现这样一个结论:一个大资源的加载,使用了13t的时间,而将大资源分解后,虽然总共用了21t的时间,但是客户端真正等待的时间却只有9t,比合并资源的方式节约了4t。

这就是并行的效果,当然要实现这个效果,是有前提的:

  • 并行的连接数没有超过浏览器的限制,这里假设4并行是一个比较合理地、照顾到各浏览器的值。
  • 服务器能顶得住,不会因为并发连接过多而导致处理时间变长。
  • 网络足够稳定,这一点将保证TCP建立、请求头发送、响应头发送这3段时间是稳定的。
  • 浏览器的资源加载不会阻塞,如IE6-7在下载js文件时会阻塞后续资源的请求,则不可能实现并行。

缓存的考虑

合并资源有另一个好处,就是在缓存之后,只需向服务器验证一次即可。但是再和拆分资源的加载过程作一个比较,如果采用带验证的缓存,不难得出下图:

服务器缓存的情况

而如果使用客户端的缓存,则是以下情况:

客户端缓存的情况

从上面2张图中可以看到,即便在有缓存的情况下,如果满足一定的条件,可以进行并发的话,若干个小资源的加载情况下客户端的等待时间和合并为一个大资源后是相同的,并没有多余的消耗。

总结

一个最基础的结论是,加载资源总用时客户端等待时间是2个完全不同的概念,他们之间并不存在正比的关系,而在宽带普及的当前时代,多数网络资源并不是按流量收费的,因此前端的优化应该更关注于客户端等待时间,而不是加载资源总用时和流量之上。

事实上,一个最经典的应用就是下载软件,从90年代的NetAnt开始,到其后的网际快车、迅雷,无一不具有“多线程下载”的能力。事实上多线程下载同样会因为线程的切换、文件分段的空间分配、最后多段碎片的拼接等导致总耗时更多,但也确确实实极大地缩短了下载的时间。在对页面的资源加载作优化时,是不是也可以参考一下这个模型呢?

由此,对资源的切分将会从单纯的“合并”的级别,提升到一种完全艺术的程度,综合考虑不同浏览器对资源加载的策略,最大限度利用浏览器的并行下载能力,从而正确、最优地分配静态资源域名,切分静态资源,压榨浏览器全部的能力,进一步地提升页面加载的速率。这虽然大大提高了资源管理、分解的复杂度,但是对于追求极限而言,本人认为这样才是真正的最佳实践。

最后,本文完全没有全部否定减少HTTP请求数这一优化原则的意思,只是希望从另外一个角度看问题,保持着一定的怀疑的心态来重新审视这一原则,拒绝不经过思考的无意义的遵循,从而寻找到在特定环境下,最适合、最优化的方案。

相关 [http] 推荐:

HTTP Headers 入门

- johnny - Time Machine
非常感谢 @ytzong 同学在twitter上推荐这篇文章,原文在此. 本文系统的对HTTP Headers进行了简明易懂的阐述,我仅稍作笔记. 什么是HTTP Headers. HTTP是“Hypertext Transfer Protocol”的所写,整个万维网都在使用这种协议,几乎你在浏览器里看到的大部分内容都是通过http协议来传输的,比如这篇文章.

HTTP基础

- - ITeye博客
HTTP的结构主要包括下面几个要点:. HTTP的版本主要有1.0,1.1 和更高版本.    1.1 及以上版本允许在一个TCP连接上传送多个HTTP协议,1.0能 .    1.1 及以上版本多个请求和响应可以重叠,1.0不能.    1.1 增加了很多的请求头和响应头.     一个请求行,若干小心头,以及实体内容,其中的一些消息头和实体内容是可选的,消息头和实体内容需要空行隔开.

HTTP Header 详解

- - 博客园_Ruby's Louvre
HTTP(HyperTextTransferProtocol)即超文本传输协议,目前网页传输的的通用协议. HTTP协议采用了请求/响应模型,浏览器或其他客户端发出请求,服务器给与响应. 就整个网络资源传输而言,包括message-header和message-body两部分. 首先传递message- header,即 http header消息.

HTTP/2 in Netty

- -
Here, we created a context for the server with a JDK SSL provider, added a couple of ciphers, and configured the Application-Layer Protocol Negotiation for HTTP/2..

HTTP负载测试

- - 博客 - 伯乐在线
英文原文: ON HTTP LOAD TESTING 来源: oschina. 有很多人在谈论HTTP服务器软件的性能测试,也许是因为现在有太多的服务器选择. 这很好,但是我看到有人很多基本相同的问题,使得测试结果的推论值得怀疑. 在日常工作中花费了很多时间在高性能代理缓存和源站性能测试方面之后,这里有我认为比较重要的一些方面来分享.

HTTP断点续传

- - CSDN博客互联网推荐文章
要实现断点续传的功能,通常都需要客户端记录下当前的下载进度,并在需要续传的时候通知服务端本次需要下载的内容片段. HTTP1.1协议(RFC2616)中定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下:.   1.客户端下载一个1024K的文件,已经下载了其中512K.

http-kit 1.2 发布

- - 开源中国社区最新新闻
Http-kit 是主要由Java 和Clojure开发,为Clojure定制的零依赖的Http lib,包括异步的高性能HTTP Server 和 HTTP Client. 在普通的PC上进行性能测试时,http-kit server 每秒能处理数万个请求. 修复处理文件上传时,content-type没能正确处理.

HTTP缓存算法

- - PHP源码阅读,PHP设计模式,PHP学习笔记,项目管理-胖胖的空间
HTTP协议缓存的目标是去除许多情况下对于发送请求的需求和去除许多情况下发送完整请求的需求. 以不发送请求或减少请求传输的数据量来优化整个HTTP架构,此目标的实现可以产生如下好处:. 降低对原始服务器的请求量. 减少了传送距离,降低了因为距离而产生的时延. 缓存基本处理过程包括七个步骤. 接收 – 缓存从网络中读取抵达的请求报文.

HTTP头部详解

- - CSDN博客推荐文章
HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP 协议的详细内容请参考RFC2616. HTTP协议采用了请求/响应模型. 客户端向服务器发送一个请求,请求头包含请求的方法、URI、协议版本、以及包含请求修饰符、客户信息和内容的类似于MIME的消息结构.

spring http invoker 实践

- - CSDN博客互联网推荐文章
搞了半天,终于把一个 Spring http invoker 的小例子运行起来了. UserServices接口:. UserServicesImpl实现类:. System.out.println("这里只是测试了一下. .