HTTP性能: 总览

所有的用户都喜欢在高速状态访问网站. 用户都是没有耐心的. 如果它的性能欠佳, 除非你的网站没有其他任何竞争对手, 否则用户是不愿意多停留在你的网站的. 如果你的网站是面向全球的访问者, 保证你的网站能有效率的运行就更加重要了, 因为要考虑到国际化网络常常会受到两个因素影响: 高延迟和低带宽.

有很多的方式可以提高你网站的性能:压缩技术,缓存,基于地理位置的负载平衡,增加硬件等到.优化压缩和缓存常常是最好用的方式,由于它们涉及的改变一般都是免费的,而且可以达到显著的效果.

在这篇文章,我们将使用Fiddler HTTP Debugger来研究HTTP性能,缓存和压缩技术.

 

调整第一次访问的性能

用户对你网站的第一次访问是非常重要的.访问者需要下载每一点的信息来生产网页,包括Jscript,CSS,图片和HTML.如果你的网页加载地太慢,访问者也许在它完成加载之前就离开了页面.

通过显示所有的 HTTP通讯,Fiddler可以轻松地显示用来生成一个页面所涉及的文件.在HTTP会话列表,Shift+点击多个记录可以计算”加载页面权重”-请求的数量和传输的字节. 
 

1. Fiddler's数据视图

 

为了提供一个”哇,这个真的很快”第一印象,最好的方式就是递送更少和更小的文件.

高速的首次访问的技巧:

  • 用更少的图像
  • 提取式样到一个独立的CSS文件
  • 提起脚本块到一个独立的JS文件
  • 简化页面布局
  • 使用HTTP压缩

只要你能提供一个高速的首次浏览体验,你就可以通过HTTP缓存为回头客来提供更快的性能.

 

HTTP缓存介绍

有两个提高你的网站速度的要素:

  • 减少请求\响应回传的次数
  • 减少服务器和客户端传输的字节数量

HTTP缓存是减少双程回传和字节传输的最好方式之一.缓存为客户端或者代理提供了一个机制,可以存储HTTP响应内容以方便后续需要,这样请求就不需要再次通过网络.

除了性能调优,最大化的利用HTTP缓存的优势还来自于网络带宽是收费的.为一个微软的主站调节缓存可以每个月节省$10,000的传出带宽开销.

 

缓存相关的请求头

为了提高性能,微软IE浏览器和其他的Web客户端会在本地维护从远处web服务器下载的缓存资源.

当客户端需要一个资源的时候,有三种可能的动作:

  • 发送一个直白的HTTP请求向远成Web服务器请求一个资源
  • 发送一个条件型的HTTP请求,当且仅当请求的资源和本地缓存的版本不一致时才到初始服务器获得该资源
  • 当请求的资源存在一个本地缓存副本的时候,使用本地缓存版本的资源

当发送一个请求的时候,客户端也许需要用到下面的头:

 

1. 客户端缓存头

Pragma: no-cache

客户端不倾向于接受任何带有缓存的响应,必须每次都联系初始服务器获取一个全新的资源.

If-Modified-Since: datetime

服务器应该返回请求的资源,当且仅当资源在客户端提供的时间戳之后被修改过的情况.

If-None-Match: etagvalue

服务器应该返回请求的资源,当资源的ETAG标记和客户端提供的值不一致的情况.ETAG是用来标记一个文件版本的独一标记.

一个客户端通过发送包括If-Modified-SinceIf-None-Match的”条件性请求”来表示它包含一个可用的缓存资源.如果服务器对条件性请求回复一个HTTP/304 Not Modified,客户端就会重用它已经有的缓存响应内容.否则,服务器回回复一个新的响应,客户端应该丢弃它缓存下来的过期内容.

下面是对同一个图像文件的两次连续请求.在第一次会话阶段,没有可用的本地缓存文件,所以服务器返回了包含ETAG值和最后一次修改时间的文件.在后面的会话中,有一个可用的本地缓存文件,所以客户端发送了一个条件性请求来传送本地缓存响应的ETAG值和最后修改时间.由于该图像没有在缓存版本后被修改过(由于ETAG值一致或者If-Modified-Since值和Last-Modified值相符), 服务器返回了一个304结果,把客户端导向到本地缓存的响应.

 

Session #1

GET /images/banner.jpg HTTP/1.1

Host: www.bayden.com

 

HTTP/1.1 200 OK

Date: Tue, 08 Mar 2006 00:32:46 GMT

Content-Length: 6171

Content-Type: image/jpeg

ETag: "40c7f76e8d30c31:2fe20"

Last-Modified: Thu, 12 Jun 2003 02:50:50 GMT

Session #2

GET /images/banner.jpg HTTP/1.1

If-Modified-Since: Thu, 12 Jun 2003 02:50:50
GMT

If-None-Match:
"40c7f76e8d30c31:2fe20"

Host: www.bayden.com

 

HTTP/1.1 304 Not Modified 

 

由于一个HTTP/304响应只包含了头部,没有数据内容,它在网络上传送比一个重新下载的整资源快很多.不管怎样,即使一个HTTP/304也需要一个完整的双程回传到远程服务器;通过仔细的设置响应头,一个web服务器开发人员甚至可以避免发送条件性请求的必要.

 

缓存相关的响应头

一般来说,HTTP响应的可缓存能力是由响应头决定的. HTTP specification描述了头部控制着缓存.Web服务器主要利用机制可选的Cache-Control和Expires头来指示代理或者客户端应该如何缓存内容.

Expires头包含了一个绝对的时间,在这个时间之后的响应缓存副本都不应该被认为全新的.如果Expires头包含一些非数字(0或者-1是正常的值)的值,该响应应该立即被当做失效的来处理.一个全新的缓存记录也许可以在不联系服务器的情况下就被重新利用;一个失效的缓存记录不应该在联系web服务器之前就被重用,这样才能保证它是最新的.

举例,在前面的例子中,我们将要添加一个Expires头到首次响应中:

 

Session #1

GET /images/banner.jpg HTTP/1.1

Host: www.bayden.com

 

HTTP/1.1 200 OK

Date: Tue, 08 Mar 2006 00:32:46 GMT

Content-Length: 6171

Content-Type: image/jpeg

Expires: Tue, 12 Jun 2007 02:50:50 GMT

Last-Modified: Thu, 12 Jun 2003 02:50:50 GMT

 

Session #2

<no HTTP request is made; cached version
is used automatically>

 

你会看到,我们通过添加Expires头提升了性能,因为第二次的会话阶段没有涉及条件性HTTP请求.

类似地,Cache-Control头包含了控制缓存的令牌列表.任何Cache-Control指令可以取代Expires头.

通常使用的Cache-Control令牌包含表2中的选项:

 

2. 通用的Cache-Control

意义

public

响应也许被储存在所有的缓存中,包括多个用户之间共享的缓存.

private

响应也许只储存在一个独立用户的私人缓存中.

no-cache

未来的任何请求都不应该重用缓存下来的响应.

no-store

缓存不应该被重用,也不应该被写入硬盘.这个标记主要是为了安全的标记敏感响应.

max-age=#seconds

在一定的时间段内,响应也许会被重用于未来的请求.

must-revalidate

响应也许会被重用于未来的请求,但是必须首先联系初始服务器来验证该响应是不是最新的.

 

注释

  • 如何配置IIS缓存的KB How to Modify the Cache-Control HTTP Header When You Use IIS.
  • 如何配置ASP.NET页面的缓存KB How To Cache in ASP.NET by Using Visual C# .NET.
  • 如果你常常需要更新你网站的文件,却不修改文件名,那么你需要注意缓存生命周期的设置.比如,this year.gif用来显示今年的年份,你需要保证缓存指令不会再超出一天的时间后都不发送标记过期, 否则在12月31号浏览网站的用户可能无法看到正确的图片当他们回到1月1号时.
  • 由于遗留问题,有时候服务器会发送 Pragma: no-cache 头, 可以将其看作为Cache-Control: no-cache.
  • Vary头会在缓存中标记该响应只有在某些特定的情况才可以重用.举例来说,Vary:User-Agent是用来示意当前的响应也许只会在被同样包含User-Agent头的请求重用.指挥性质的Vary: *Cache-Control: no-cache.是一样的作用.

 

在Fiddler的HTTP会话列表,可以很容易的看到那些页面包含那些HTTP缓存头.


2. Fiddler会话列表

 

如果一个响应不包含ExpiresCache-Control头,那么客户端也许会被强制发送一个条件性请求来保证资源是全新的.

 

条件型请求和WinInet 缓存

IE通过利用微软Windows Internet Services提供的缓存服务获益.

WinInet允许用户配置缓存的大小和行为.访问缓存设置的方式为:

  1. 打开IE
  2. 点击工具>Internet选项
  3. 常规选项卡,在临时文件区域点击设置

设置对话框,最上面有四个选项:

3. IE缓存选项

大部分的用户会保留默认设置-自动.

应该记住的最重要的事情是这四个选项大部分情况是在在HTTP响应不包含缓存头的时候来影响IE行为的;当缓存头可用的时候,IE会一直考虑他们.下面的表描述了这些选项在IE处理请求的行为上的影响.

 

3. 缓存行为

设置

缓存副本是全新的

缓存失效

没有可用的缓存指令

每次访问网页时

不请求

条件性请求

条件性请求

每次 启动IE

不请求

条件性请求

条件性请求

自动

不请求

条件性请求

探索式的 (详见下文)

从不

不请求

条件性请求

不请求

如果请求是初始响应的Cache-ControlExpires头写明的鲜活生命周期内产生的,那么缓存的内容被认为是全新的.如果请求是在写明的生命周期之后产生的,那么缓存内容则是失效的stale.

自动设置能够智能的接受一些说明 - 当HTTP响应没有提供任何缓存指令时,WinInet是怎么知道缓存的资源是最新的呢?

答案是WinInet不能确定,所以探索进程开始尝试寻找最佳的答案.在自动设置状态,探索会产生一个条件型请求,除非以下的所有条件都满足:

  • 缓存资源接受image/开头的Content-Type.
  • 缓存资源有一个Last-Modified时间.
  • 缓存资源的URL不包含问好标记(暗示着它是一个CGI请求).
  • 缓存资源在它寿命的最近25%内,曾经至少被条件型的请求询问过一次.

如果以上的所有条件都满足,不需要发送请求.

作为一个web开发人员,你应该做到一直保证你能发送合适的缓存头来确定你可以获得最佳的缓存行为.

 

标记性能问题

你可以用Fiddler的自定义规则来关注潜在的性能问题.比如,你可以标记所有大于25KB的响应.

添加规则,点击Rules然后Customize Rules,把下面的代码写进OnBeforeResponse事件处理器:

// Flag files over 25KB

   if
(oSession.responseBodyBytes.length > 25000){

     
oSession["ui-color"] = "red";

     
oSession["ui-bold"] = "true";

     
oSession["ui-customcolumn"] = "Large file";

   }

类似的,你也可以标记不包含任何缓存内容的响应:

   //
Mark files which do not have caching information

if
(!oSession.oResponse.headers.Exists("Expires") &&

!oSession.oResponse.headers.Exists("Cache-Control")){

     

oSession["ui-color"] =
"purple";

     
oSession["ui-bold"] = "true";

   }

 

HTTP压缩介绍

所有流行的web服务器和浏览器都支持HTTP压缩技术.HTTP压缩技术能够显著地减少服务器赫尔客户端之间传送的字节数量;超过50%的HTML, XML, CSS和JS节省是很常见的.

一个web浏览器通过在请求头陈列它支持的压缩类型, 来向服务器标记它自己愿意接受HTTP压缩内容.举例,请考虑下面发送到新的MSN Search首页的请求:

 

GET / HTTP/1.1

Accept: */*

Accept-Language: en-us

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE
6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)

Host: search.msn.com

 

Accept-Encoding头表明IE愿意接受被GZIP或DEFLATE格式压缩后的响应.

MSN Search服务器相应的返回了压缩的内容; Content-Encoding响应头表明响应使用的是GZIP格式.

 

HTTP/1.1 200 OK

Content-Type: text/html; charset=utf-8

Server: Microsoft-IIS/6.0 --Microsoft-HTTPAPI/1.0

X-Powered-By: ASP.NET

Vary: Accept-Encoding

Content-Encoding: gzip

Date: Tue, 15 Feb 2006 09:14:36 GMT

Content-Length: 1277

Connection: close

Cache-Control: private, max-age=3600

 

使用Fiddler,你可以通过Transformer工具来解压缩响应.

 

4. 在解压缩GZIP响应之前的Transformer Inspector

点击No Compression按钮来解压该响应.压缩已经减少了超过了57%的传输字节.


5. 在解压缩之后的Transformer Inspector

在IIS中为静态文件启动压缩对IIS Web服务器的CPU影响很低,因为这些
文件只有在第一次才会被压缩然后就缓存在服务器上.为动态文件,比如ASP.NET页面启用压缩也许会对服务器的CPU性能造成影响;你会需要在为生成环境的web服务器启用动态压缩之前评估这个影响.

 

突破性能瓶颈

提高HTTP效率只是挑战的一半内容;如果你的web程序本身很慢,那么不管HTTP通讯多么有效,速度也不会快的.参阅Ten Tips for Writing High-Performance Web Applications关于性能优化.

 

原文: http://msdn.microsoft.com/en-us/library/bb250442(VS.85).aspx

 

谢谢.

许亚男Leola