AD 01

让您的网站更好的配合CDN --如何配置web服务器以提高缓冲兼容性

1.缓冲的基本原理

缓冲服务器是在浏览器和网页服务器之间的一组(台)机器,主要作用有两个:一是减少网络流量,二是减少网络延迟。减少网络流量主要是减少缓冲服务和原始的网页服务器之间的流量。减少网络延迟是减少了应答客户端浏览器的延迟。为了实现这些功能,在HTTP/1.1和HTTP/1.0协议里面有相关的命令来控制缓冲的行为。

缓冲服务器可以靠近原始服务器端也可以靠近浏览器端,靠近服务器端的代理服务器一般叫做反向代理。微睦网络的代理服务器集群就属于这种模式。
缓冲服务器利用两个基本的概念来管理缓存的内容,一是新鲜度,二是有效性检查。一个被缓存的内容(比如一张图片)在有效期内,缓冲服务器可以直接把这个内容返回给浏览器(客户端)。如果一个被缓存的内容过期了,那么缓冲服务器就会认为这个内容是"陈旧"的,就会去原始服务器验证这个内容是否已经更新。如果已经更新了,那么就会把更新过的内容下载到缓冲服务器,然后重新开始计算该内容的新鲜时间。

一个内容的过期时间可以由服务器端通过http头信息来明确指定,比如通过一个名为Expires的http头来指定,如下面的例子:

http://www.google.com/intl/zh-CN_ALL/images/logo.gif
Expires  1641 weeks 2 days from now  (Sun, 17 Jan 2038 19:14:07 GMT)

这是google中国的logo图片,它的过期时间是2038年1月17日。
那如果这个图片在中途被修改过了怎么办?没关系,假如一个浏览器(比如firefox)对这个图片进行一下刷新,浏览器就会发送一个带条件的请求,而缓冲就会去真实服务器检查这个图片是否已经更新,如果图片更新了,那么缓冲服务器就会把新的内容下载过来替代旧的内容。

缓冲服务器验证内容有效,是通过一些条件来判断的,比如最后修改时间,或者是一个叫做 ETag 的 http 头信息。具体的细节就不用去了解了。

2. 如何让你的网页内容具有更好缓冲友好性

为什么要对缓冲友好?因为如果有更多的内容被缓冲服务器所缓冲,那么你的网站本身的负载就降下来了,因为很多请求都由缓冲服务器代你应答了,假如浏览器请求下载你的网页里的小图片,如果每个这样的请求都要你的网页服务器来处理,必然降低你的网页服务器的处理能力。

那么在哪里设置,如何设置呢?这取决于你使用的网页服务器,现在流行的就是windows下的IIS和Unix/Linux下的Apache,下面分别讲解。

Apache

在Apache里主要是通过选择性的模块来设置头信息,头信息是 Expires 和 Cache-Control 模块是mod_expires 和 mod_headers
利用 httpd -l 命令确认你的apache已经包含了这些模块;然后就可以在你的配置文件里使用命令来控制你的内容的新鲜期了。可以对一个目录设置,也可以对文件类型进行设置。
比如下面的命令将图片文件的新鲜期设置成1年。更详细的配置说明请参考apache的文档。(http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_expires.html)

    ExpiresActive on
    ExpiresByType image/* "access plus 1 year"

利用这些命令,你可以给你的图片文件和静态的文件设置一个合理的新鲜时间。而不用担心用户不能看到你最近的更新,正如刚才所说,如果用户点浏览上的刷新按钮,最新的内容就能被访问到。

IIS 服务器

在iis管理器中右键单击某一网站或目录,属性,http 头。设置相应的过期策略,对于不经常更新的页面可设定比较高的值。如2小时,1天等。需要经常更新的数据设定比较小的值,10分钟,20分钟。这个时间越长,CDN效果越好,您的真实服务器负载也越小,但有些内容又必须及时刷新,站长可以慢慢调整这个时间,找到一个最佳平衡点.

3. 在CDN后面的真实服务器端如何得到访问者ip地址

由于真实服务器和浏览器之间有CDN的缓冲服务器,真实服务器得到的访问ip是缓冲服务器的ip地址。但是缓冲服务器通常会在HTTP 头里包含真实客户端的ip地址,在Squid(一种流行的缓冲服务器)里通常增加一个X-Forwarded-For头信息来包含原始的客户端ip.所以要在Apache服务器的日志里得到这个ip,可以增加一个%{X-Forwarded-For}i 到相应LogFormat里面。
如果想在web程序里得到这个值,可以通过所用语言的相关函数得到这个值,比如说在php里面,可以利用getenv函数得到。

4.可缓存的动态页面设计

什么样的页面能够比较好的被缓冲服务器缓存呢?如果返回内容的HTTP HEADER中有"Last-Modified"和"Expires"相关声明,比如:

Last-Modified: Wed, 14 May 2003 13:06:17 GMT
Expires: Fri, 16 Jun 2003 13:06:17 GMT

前端缓存服务器在期间会将生成的页面缓存在本地:硬盘或者内存中,直至上述页面过期。
因此,一个可缓存的页面:
页面必须包含Last-Modified: 标记
一般纯静态页面本身都会有Last-Modified信息,动态页面需要通过函数强制加上,比如在PHP中:
// always modified now
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");

必须有Expires或Cache-Control: max-age标记设置页面的过期时间:
对于静态页面,通过apache的mod_expires根据页面的MIME类型设置缓存周期:比如图片缺省是1个月,HTML页面缺省是2天等。

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresByType image/gif "access plus 1 month"
    ExpiresByType text/css "now plus 2 day"
    ExpiresDefault "now plus 1 day"
</IfModule>

对于动态页面,则可以直接通过写入HTTP返回的头信息,比如对于新闻首页index.php可以是20分钟,而对于具体的一条新闻页面可能是1天后过期。比如:在php中加入了1个月后过期:
// Expires one month later
header("Expires: " .gmdate ("D, d M Y H:i:s", time() + 3600 * 24 * 30). " GMT");

如果服务器端有基于HTTP的认证,必须有Cache-Control: public标记,允许前台
ASP应用的缓存改造 首先在公用的包含文件中(比如include.asp)加入以下公用函数:

<%
' Set Expires Header in minutes
Function SetExpiresHeader(ByVal minutes)
    ' set Page Last-Modified Header:
    ' Converts date (19991022 11:08:38) to http form (Fri, 22 Oct 1999 12:08:38 GMT)
    Response.AddHeader "Last-Modified", DateToHTTPDate(Now())
    ' The Page Expires in Minutes
    Response.Expires = minutes
    ' Set cache control to externel applications
    Response.CacheControl = "public"
End Function
' Converts date (19991022 11:08:38) to http form (Fri, 22 Oct 1999 12:08:38 GMT)
Function DateToHTTPDate(ByVal OleDATE)
  Const GMTdiff = #08:00:00#
  OleDATE = OleDATE - GMTdiff
  DateToHTTPDate = engWeekDayName(OleDATE) & _
    ", " & Right("0" & Day(OleDATE),2) & " " & engMonthName(OleDATE) & _
    " " & Year(OleDATE) & " " & Right("0" & Hour(OleDATE),2) & _
    ":" & Right("0" & Minute(OleDATE),2) & ":" & Right("0" & Second(OleDATE),2) & " GMT"
End Function
Function engWeekDayName(dt)
    Dim Out
    Select Case WeekDay(dt,1)
        Case 1:Out="Sun"
        Case 2:Out="Mon"
        Case 3:Out="Tue"
        Case 4:Out="Wed"
        Case 5:Out="Thu"
        Case 6:Out="Fri"
        Case 7:Out="Sat"
    End Select
    engWeekDayName = Out
End Function
Function engMonthName(dt)
    Dim Out
    Select Case Month(dt)
        Case 1:Out="Jan"
        Case 2:Out="Feb"
        Case 3:Out="Mar"
        Case 4:Out="Apr"
        Case 5:Out="May"
        Case 6:Out="Jun"
        Case 7:Out="Jul"
        Case 8:Out="Aug"
        Case 9:Out="Sep"
        Case 10:Out="Oct"
        Case 11:Out="Nov"
        Case 12:Out="Dec"
    End Select
    engMonthName = Out
End Function
%>

然后在具体的页面中,比如index.asp和news.asp的“最上面”加入以下代码:
HTTP Header
<!--#include file="../include.asp"-->
<%
'页面将被设置20分钟后过期
SetExpiresHeader(20)
%>

5. 如何检验缓冲服务器如何对待你的网页内容

打开这个网址:(http://utils.vmmatrix.net/)
然后根据提示,输入你想检查的内容的URL(地址),就可以看到这个内容的Http头信息,和缓冲如何处理这个URL.大多数情况有两种,一是明确指定了新鲜时间,所以缓冲服务器在新鲜时间内认为这个内容是新鲜的。二是没有明确指定新鲜时间,缓冲服务器就会根据这个内容的最后修改时间距离现在的时间作为一个时间段,然后把这个时间段的一个百分比来作为新鲜时间,这个百分比是在缓冲服务器哪里设置的。
如果一个内容既没有明确指定新鲜时间,也没有最后修改时间,那么缓冲服务器就会把这个内容当做是”陈旧“的内容,每次都会去原始服务器验证。