Archive for the ‘squid’ Category.

squid反向代理:消息的可缓存性

最近,我们团队计划将memcached运维起来,突然想起之前自己做过相关squid反向代理的文章,有点时间了,翻出来都有点发霉了,呵呵,先保存在这里,有空回忆一下,哈哈。

Hosting Imporvement
消息的可缓存性

目 录
目 录 2
1 修订记录 3
2 介绍 4
2.1 目的和范围 4
2.2 术语与缩写解释 4
3 可缓存实体 5
3.1 按状态码分类的response可缓存性 5
3.2 cache-control response可缓存性 5
3.3 Response响应的过期与保鲜 8
3.4 Validation验证 10
4 其他建议 11
4.1 进一步工作 11
5 相关文档列表 12

1修订记录

修订日期 版本号 描述 修订人
2008/06/27 0.1 消息的可缓存性v0.1 Pickup.Lichun

2介绍
2.1目的和范围
本文档的目的介绍HTTP消息的缓存以及相关信息。
cache服务器作为反向代理可以减少后端web服务器的访问压力并提高用户的访问速度,但是cache服务器到底可以缓存那些东西,可以缓存多久,怎么控制某个消息过期以后的动作等等。这些都是本文档关注的内容。
本文介绍的内容主要来源是HTTP 1.1,某些缓存服务器通过一定的配置(比如:squid配置中refresh_pattern的ignore-private等)能够显式的违反某些规则,所以具体的某个消息的缓存还依赖于缓存服务器的配置及相关因素,需要具体问题具体分析。
另外,本文关注的主要是做反向代理的缓存服务器。

2.2术语与缩写解释
编号 术语 解释
1. message 消息,HTTP通讯的基本单元,通常指request或者response消息
2. request 请求,客户端向服务器发送的请求
3. response 响应,服务器对客户端请求的响应
4. cache 缓存,存储在本机的response信息,以及对这些信息的存储,获取,删除等。这些信息存储以便在相同的request请求时能够及时返回,从而减少响应时间和网络流量的消耗。
5. cacheable 可缓存,某个response信息如果可以存储在下来以供接下来同样的request请求使用,那么这个信息可以被认为作可缓存的。即使某个response是可以缓存的,当一个特定的request请求到达时,是否返回该response还要受到一些附加的条件限制
6. explicit expiration time 显式的过期时间,源服务器指定的过期时间,当过了过期时间以后cache服务器返回相应response之前必须经过验证。
7. heuristic expiration time 启发式的过期时间,当没有显式的过期时间时由cache服务器生成的过期时间
8. age 年龄,一个response的年龄值就是它从被源服务器发送或者验证之后经过的时间值
9. freshness lifetime 保鲜时间,它表示从response生成到过期之间经过的时间值
10. fresh 保鲜的,如果一个response的age没有超过freshness lifetime则被认为是保鲜的
11. stale 过期的,如果一个response的age超过了freshness lifetime则被认为是过期的
12. validator 验证子,用于确认cache保存的实体是否和源服务器一致的协议元素(比如:Last Modified time或者一个entity tag)
13. Shared and Non-Shared Caches
共享和不可共享cache,不可共享cache是指那些只能被单个用户访问的cache,访问它必须经过相关的权限认证,其他的cache都是共享cache。

3可缓存实体
在Squid Cache服务器安装配置与测试数据中,经过测试和分析,发现cache服务器不仅可以为web服务器分担压力,并且能够提高用户访问时的速度。以squid为例,网站用 squid 加速,目的有二
1: squid 本身具有缓存功能,可以将webserver输出的内容缓存起来,在缓存没有过期之前来的访问,都直接用缓存里面的内容,这样可以有效减少 webserver 机器上面的请求数量。这是 squid 的主要功用。
2: 网络慢的用户会长时间占用 webserver 的 TCP 连接,webserver 对每个连接占用的资源比较大,如果长时间不能释放出来服务其他请求,性能会有比较大的影响。前面放一个 squid,webserver 就可以迅速处理完逻辑以后,把数据快速发送给 squid, 然后去处理别的逻辑,而 squid 每个 TCP 连接占用的资源很少,不用担心占用太多资源。这个用途也叫做连接管理,有一些网络设备也可以做这个事情,价格都很贵。
所以我们有必要搞清楚哪些东西可以缓存,哪些不能被缓存,怎么控制,为网页制作人员和web service维护配置人员提供指导。

3.1按状态码分类的response可缓存性
我们知道,response按照状态码可以分成5类,分别是1xx信息类,2xx成功类,3xx重定向类,4xx客户端错误类和5xx服务器错误类。这里可以被缓存的response只有状态码为:200, 203, 206, 300, 301 或者 410的response。其他的response除非由cache-control或者其他的header显式指定(比如:cache-control中的 “max-age”, “s-maxage”, “mustrevalidate”,“proxy-revalidate”, “public” 或 “private”),否则都不能被缓存。

3.2cache-control response可缓存性
cache-control定义了一系列request/response链上的cache服务器必须要遵守的规则。这些规则大部分会改变缺省的cache算法。cache-control的基本语法格式为:
Cache-Control = “Cache-Control” “:” 1#cache-directive
1#cache-directive表示一个或者多个cache-directive,cache-directive可能是cache-request-directive也有可能是cache-response-directive。
cache-request-directive包括:”no-cache”, “no-store”, “max-age=’delta-seconds'”, “max-stale[=’delta-seconds’]”, “min-fresh=’delta-seconds'”, “no-transform”, “only-if-cached”和cache-extension。其中,”max-stale”可以指定以秒为单位的时间值,”max-age”和”min-fresh”则必须指定以秒为单位的时间值。
cache-response-directive包括:”public”, “private[=’1#field-name’]”, “no-cache[=’1#field-name’]”, “no-store”, “no-transform”, “must-revalidate”, “proxy-revalidate”, “max-age=’delta-seconds'”, “s-maxage=’delta-seconds'”, cache-extension。其中,”max-age”和” s-maxage”必须指定以秒为单位的时间值,” private “和” no-cache “可以带一个或者多个HTTP header域从而指定这些header不能缓存。cache-extension是类似community=”UCI”的cache-control扩展标签,它可以用于自定义的cache缓存协议元素,比如community=”UCI”作为Private的附带元素可以表示该条response信息只能被私有的标识为“UCI”的cache缓存,其他的cache都不能缓存它。
首先,我们介绍一些影响response可缓存性的cache-control规则:”public”, “private[=’1#field-name’]”, “no-cache[=’1#field-name’]”。
”public”表示该response可以被缓存,就算平常被认为不能缓存或者只能被non-shared cache缓存的那些response也可以。
”private”表示该response的全部或者某一部分是为单个用户服务的,不可以被shared cache缓存,源服务器可以用它来标示该response隶属于某个用户而不能为其他用户服务。私有(non-shared)cache可以保存这些消息,但是”private”并不能保证消息内容的私密安全性。
”no-cache”,如果no-cache没有特别指定某些field-name,那么它表示cache如果需要返回该response给接下来的request之前必须先向源服务器验证,否则不能发送。这样,源服务器就可以用它来强制cache验证该response,即使cache被设置为可以返回过期的response给用户。如果no-cache附带了一些field-names,cache可以受限的返回response,也就是说返回的response中对应的这些特定的field-names在返回之前必须经过验证,这样源服务器可以限制某些header不会被重用,从而使得这些header都是最新的。
接下来我们来看看影响cache存储response的cache-control规则:”no-store”。
cache可存储reponse和response的可缓存性是不同的。为了避免某些敏感数据不被cache存储下来,可以指定”no-store”,它作用于整个request或者response消息。指定了”no-store”的request表示该request以及由它引起的response都不能被存储,指定了”no-store”的response表示该response以及引起它的request都不能被存储。它对non-shared cache和shared-cache都有效。也就是说cache不能故意的把它存储在永久存储设备上,并且在转发了它以后应该及时清除易失存储设备上的信息。”no-store”提供了一定的私密安全保证,但是某些cache也许不会遵守该约定,也有可能被浏览器本身缓存下来了(当用户点击后退按钮可以访问),并且也可以通过网络监听获得对应的数据。
接着介绍一下影响过期机制的一些cache-control规则:”max-age”, “s-maxage”,”max-stale”和”min-fresh”。其中”max-age”可以应用于request或者response。
作用于response的影响过期机制的一些cache-control规则
“max-age”:过期时间有源服务器的”Expires”头指定,也可以由”max-age”规则指定。”max-age”优先于”Expires”头(即使”Expires”头限制的时间值更加严格),当一个response年龄值大于过期时间时,它被认为是过期的,返回过期的数据需要经过验证或者后面提到的cache-control规则的作用。事实上,”max-age”暗示了该repsonse可以被缓存,除非指定了一些别的更加严格的cache规则。HTTP 1.0没有制定”max-age”规则。
“s-maxage”:”s-maxage”总是被private cache忽略。对于shared cache,它指定了response的最高生命期。它的优先级比”max-age”和”Expires”都要高。”s-maxage”在语义上包含了”proxy-revalidate”,也就是说,cache服务器在返回一个过期的response之前必须要首先提交源服务器进行验证。
作用于request的影响过期机制的一些cache-control规则
“max-age”:在request中包含”max-age”表示客户端同意接受一个age小于指定秒数的response。如果没有指定”max-stale”那么客户端并不同意接受一个过期的response。
“min-fresh”:表示客户端同意接受一个freshness_lifetime不小于当前age值+指定秒数的response。也就是说客户端希望收到的response的新鲜度至少在指定秒数以内。
“max-stale”:表示客户端同意接受一个过期的response消息。如果指定了时间值,表示客户端同意接受一个超过过期时间不大于指定秒数的response消息。如果没有指定具体的数值,表示客户端同意接受一个超过过期时间任意值的response消息。但是,不管是由于用户指定了”max-stale”还是cache服务器被配置为返回过期的数据,cache服务器必须给这个过期的数据加上Warning 110(Response is stale)头。
我们发现,”max-age”即可以应用于request也可以应用于response,如果request和response都包含了”max-age”,那么应该以它们两个中的值更小的那一个为准。
上面,我们提到了cache数据过期后需要提交源服务器进行验证,cache-control同样存在影响验证的规则:”max-age”,”only-if-cached”,”must-revalidate”和”proxy-revalidate”。
“max-age”:客户端提交request的时候可以加上不带field-names的”no-cache”(如果是HTTP 1.0客户端可以用”Pragma: no-cache”)来获得源服务器上的response版本从而使cache也装入这个版本。如果使用”max-age=0″附带于request上,可以使得从客户端到源服务器链路上的所有cache已有的对应response都提交源服务器进行验证,并且把该response装入那些没有存储该response的cache服务器中。当链路中的某台cache服务器收到”max-age=0″的request请求,并且该请求中还附带了validator,而该validator于cache验证的validator不同时,cache服务器可以选择自己的或者附带的validator(比较好的方法是使用cache服务器自己的validator),这样在服务器收到200或者304响应的时候可以根据具体的情况更新缓存,并给客户端发送正确的响应。另外,如果request中包含了”no-cache”就不应该包含”max-age”,”max-stale”和”min-fresh”。
“only-if-cached”:在某些情况下(比如网络情况非常差),客户端可能希望获得cache服务器中存储的response,而要求验证或者从源服务器重新获得对应response消息,用户就可以在request中包含”only-if-cached”。收到这样的请求的cache服务器可以返回本地存储的相应response,或者504(Gateway Timeout)错误信息。如果它属于构建的cache服务器集群,那么它也可以将这个请求转发给集群的其他cache服务器。
“must-revalidate”:上面提到,用户指定”max-stale”或者cache服务器被配置为返回过期的数据都可以导致过期消息的返回。而”must-revalidate”是源服务器用于指定response在过期后必须到源服务器进行验证的规则,不管用户是否指定了”max-stale”或者cache服务器是否被配置为返回过期的数据。它为某些协议特性提供了可靠性操作。如果cache验证时不能连上源服务器,它必须返回504(Gateway Timeout)错误信息。
“proxy-revalidate”:除了不能够应用于non-shared cache以外,”proxy-revalidate”和”must-revalidate”的意思是一样的。它允许在用户cache中保存那些经过权限认证的response(它们 应该包含有”public”来保证它们可以被缓存)并且在认证过同样的request到达时返回缓存数据而不经过源服务器验证过程;其他的则每次都必须经过验证。
最后我们介绍一下”no-transform”规则。为了某些原因,一些cache服务器在保存和传输消息的时候可能会转变实体主体的媒体类型。比如为了降低缓存空间或者在较慢的链接中减少传输流量,cache服务器可能会把一个图片的格式转换一下。但是某些应用场景下,数据的传输一个bit也不能转换,这里”no-transform”就非常必须了。如果一个消息中包含了”no-transform”,那么非修改头部及其指定的消息主体部分都不能转换或者改变,这些非修改头部包括”Content-Location”, “Content-MD5”, “ETag”, “Last-Modified”, “Expires”, “Content-Encoding”, “Content-Range”, “Content-Type”(参见HTTP 1.1 section 13.5.2)
一般说来:遵循以下基本的规则
1.如果响应头信息:告诉缓存器不要保留缓存,缓存器就不会缓存相应内容;
2.如果请求信息是需要认证或者安全加密的,相应内容也不会被缓存;
3.如果在回应中不存在校验器(ETag或者Last-Modified头信息),缓存服务器会认为缺乏直接的更新度信息,内容将会被认为不可缓存。
4.一个缓存的副本如果含有以下信息:内容将会被认为是足够新的
o含有完整的过期时间和寿命控制头信息,并且内容仍在保鲜期内;
o浏览器已经使用过缓存副本,并且在一个会话中已经检查过内容的新鲜度;
o缓存代理服务器近期内已经使用过缓存副本,并且内容的最后更新时间在上次使用期之前;
o够新的副本将直接从缓存中送出,而不会向源服务器发送请求;
5.如果缓存的副本已经太旧了,缓存服务器将向源服务器发出请求校验请求,用于确定是否可以继续使用当前拷贝继续服务;

3.3Response响应的过期与保鲜

3.3.1age的计算方法
先介绍一下一个响应的age的计算方法。
/*
* age_value: is the value of Age: header received by the cache with this response.
* date_value: is the value of the origin server’s Date: header
* request_time: is the (local) time when the cache made the request that resulted in this cached response
* response_time: is the (local) time when the cache received the response
* now: is the current (local) time
*/
apparent_age = max(0, response_time – date_value);
corrected_received_age = max(apparent_age, age_value);
response_delay = response_time – request_time;
corrected_initial_age = corrected_received_age + response_delay;
resident_time = now – response_time;
current_age = corrected_initial_age + resident_time;

3.3.2过期时间的计算方法
过期时间主要分为explicit expiration time和heuristic expiration time,强烈建议用户指定explicit expiration time,因为只有网页制作者更加清楚这个网页的过期时间。
先介绍一下explicit expiration time的计算方法。
客户可以通过设置Expires或者Cache-control的max-age(max-age优先级大于Expires)来指定explicit expiration time。我们测试了html和php语言设置Expires的方法,并且使用ethereal观察了传输的HTTP信息,在我们的环境下,发现使用html设置header meta不能反映到HTTP header中去,而php的header()函数则能够成功。
php设置HTTP头的方法很简单,只要调用函数header()就可以了,假如我们新建一个名为testHeader.php的文件并将其内容修改为:

当用户访问该网页时我们可以传输的信息找到这两个(Expires和Content-Language)HTTP头。
meta是用来在HTML文档中模拟HTTP协议的响应头报文。meta 标签用于网页的与中,meta 的属性有两种:name和HTTP-equiv。name属性主要用于描述网页,以便于搜索引擎机器人查找、分类。HTTP-equiv顾名思义,相当于HTTP的文件头作用,它可以向浏览器传回一些有用的信息,以帮助正确和精确地显示网页内容,与之对应的属性值为content,content中的内容其实就是各个参数的变量值。
meat标签的HTTP-equiv属性语法格式是:<meta HTTP-equiv=”参数” content=”参数变量值”> ;其中HTTP-equiv属性主要有以下几种参数:
A、Expires(期限)
说明:可以用于设定网页的到期时间。一旦网页过期,必须到服务器上重新传输。
用法:<meta HTTP-equiv=”expires” content=”Fri, 12 Jan 2001 18:18:18 GMT”>
注意:必须使用GMT的时间格式。
B、Pragma(cache模式)
说明:禁止浏览器从本地计算机的缓存中访问页面内容。
用法:<meta HTTP-equiv=”Pragma” content=”no-cache”>
注意:这样设定,访问者将无法脱机浏览。
C、Refresh(刷新)
说明:自动刷新并指向新页面。
用法:<meta HTTP-equiv=”Refresh” content=”2;URL=HTTP://www.webjx.com”>
注意:其中的2是指停留2秒钟后自动刷新到URL网址。
D、Set-Cookie(cookie设定)
说明:如果网页过期,那么存盘的cookie将被删除。
用法:<meta HTTP-equiv=”Set-Cookie” content=”cookievalue=xxx; expires=Friday, 12-Jan-2001 18:18:18 GMT; path=/”>
注意:必须使用GMT的时间格式。
E、Window-target(显示窗口的设定)
说明:强制页面在当前窗口以独立页面显示。
用法:<meta HTTP-equiv=”Window-target” content=”_top”>
注意:用来防止别人在框架里调用自己的页面。
F、content-Type(显示字符集的设定)
说明:设定页面使用的字符集。
用法:<meta HTTP-equiv=”content-Type” content=”text/html; charset=gb2312″>
我们在index.htm中的

中加入了:

但是用户访问网页时返回的response的HTTP header中找不到Expires。

接下来,介绍一下heuristic expiration time的计算方法。
而freshness_lifetime计算方法如下:
如果存在cache-control的max-age(或者s-maxage)值,则:freshness_lifetime = max_age_value
否则如果存在Expires值,则:freshness_lifetime = expires_value – date_value
如果上述两个值都不存在,而且响应中也没有包含其他的限制条件时,cache服务器可以使用一种启发式规则来计算获得freshness_lifetime(如果计算得到的freshness_lifetime大于24小时并且年龄值也超过24小时则必须在response响应中增加warning 113),但响应中包含有Last-Modified值时,原则上freshness_lifetime不应该超过从Last-Modified到现在经过的时间值的一定比例(比如:10%)。这个计算freshness_lifetime启发式规则是由cache服务器自己制定的。比如,squid的启发式规则主要是由用户制定的refresh_pattern规则指定。

3.3.3过期或者保鲜
当age值和freshness_lifetime都得到了以后,计算一个响应是否过期就简单了:
response_is_fresh = (freshness_lifetime > current_age)

3.4Validation验证
在HTTP1.1中对缓存进一步提出了验证的概念。验证的目的就是检验缓存项目是否在有效期内。当cache服务器存在一个过期的消息,并且对应的request请求到达时,它应该首先向服务器或者链路上的其他保存有未过期的cache服务器请求验证来确定本地的response是否可用。这个过程就是一个cache消息的验证过程。HTTP 1.1提供了有条件的请求返回方法(conditional methods),这样当本地response是可用时就可以减少网络流量不用传输整个response的信息,而当本地response不可用时也可以减少链路上请求多一个来回的消耗。当源服务器生成了一个完整的response时,它会附带一个验证子(validator);cache服务器可以保存它,在response过期以后,可以利用它生成一个有条件的request以向源服务器请求验证。而服务器(源服务器或者链路上保存有未过期的cache服务器)收到这样的请求以后就可以用它与自己的validator比较,如果相等,那么只返回一个带有特定状态码(通常是:304 Not Modified),并且消息主体为空的response,在这种情况下就减少了网络流量;如果两个validator不相等就传输一个完整的response,在这种情况下避免了客户端再次提交request,从而减少了一次通讯往返。事实上,所谓的有条件的request和普通的request是一样的,只是它包含了一个特殊的Header和validator。并且有条件的验证包括正验证和负验证,如果request中要求服务器与附带的validator必须相等的是正验证,如果要求两者不相等的是指负验证。
validator主要包括Last-Modified Dates和Entity Tag Cache Validators两种,分别对应了”Last-Modified”和”ETag”两个Header。当一个response在”Last-Modified”之后没有被修改过可以认为它是有效的。它是被经常用来验证一个response是否有效的validator。它对应的对应的request请求头包括:”If-Modified-Since”,”If-Unmodified-Since”。但是,”Last-Modified”是有缺陷的,因为HTTP协议的时间值是以秒为单位的,如果一个response在一秒内被修改了两次,那么验证某个response是否一致就没有办法了。所以在这种情况下或者源服务器希望避免使用时间的修改来匹配两个数据时,就可以用”ETag”。”ETag”可以由源服务器指定计算方法,根据response生成,它是一个不透明的validator。对应的request请求头包括:”If-Match”,”If-None-Match”,”If-Range”。
两个validator之间的比较可以分为强验证子比较或者弱验证子比较。强验证子比较表示每一个字节都要相等,而弱验证子比较主要是指实体相等,可以在不明显改变语义的基础上相互替换。弱验证子比较仅仅用于在弱验证子上的比较,比如:在Entity Tag前面有”W/”则表示这是一个弱validator。一个实体的修改时间可以被认为是弱验证子。弱验证子可以应用于不要求精确一致的情况下,强验证子比较应用比较广泛,几乎所有的场合都可以用。如果用户提交的request只需要response的一部分(sub-range)那么必须要保证使用强验证以获得正确的数据。

4其他建议

4.1进一步工作
了解apache和squid的cache实现以及相关配置,并结合本公司网站以及相关数据部署和测试。加快用户访问速度,提交同时可访问的用户数,加强它们的鲁棒形以及服务可用性。为以后公司的产品和项目提供支持。
另外,研究网页制作者增加缓存头部域需要遵守的规范,为网页制作者有意识的增加缓存,控制缓存时间等提供参考。

5相关文档列表
HTTP 1.1
Squid Cache服务器安装配置与测试数据
squid服务器用户手册 v0.2