1.减少网络带宽的消耗:
缓存副本被使用时,只会产生极小的网络流量。
2.降低服务器负荷
用户可以重复的使用本地缓存,减少对服务器的请求,间接降低服务器的压力。同时,搜素引擎的爬虫机器人也能根据过期机制降低爬取的频率,也能有效降低服务器的压力。
3.减少网络延迟,加快页面加载速度
缓存所带来的性能影响可以采用命中率和非命中率两个参数。命中指的是缓存直接响应客户端的请求,缺失指的是缓存不能响应到客户端的请求,然后将请求转发给远端的server。通俗的讲,前者是缓存直接将结果返回给server,而后者是缓存不存在,客户端直接从服务器获取结果。
一般情况下,缓存的内容均存在一定的时效性,因此需要经常对缓存中的内容做有效性检查(fresh check),也叫“重验证”。触发对缓存中的内容重验证的方法很多,后面的章节将会介绍到。
上图描述了缓存命中、缺失以及重验证三种情形。重验证并不代表缓存中的内容一定过时的,它仅仅表示重验证触发条件收到,需要对缓存内容做重验证。
缓存一般可以分成个人缓存(或者私有缓存)和共享缓存(“共有缓存”),比如在个人PC机上的缓存一般称为私有缓存,而对于门户网站,它们为了快速地响应各地用户请求,都会在CDN网络上建设自己的公共代理缓存(public proxy cache)。
首先要明白的是更新操作主要是为了保证缓存中的内容与服务器的内容保持一致,HTTP协议规范中规定流量两条途径:定义文档过期日期以及执行重验证。
Header
description
If-Modified-Since:<date>
Perform the requested method if the document has been modified since the specified date. This is used in conjunction with the Last-Modified server response header, to fetch content only if the content has been modified from the cached version.
If-None-Match: <tags>
Instead of matching on last-modified date, the server may provide special tags (see “ETag”)on the document that act like serial numbers. The If-None-Match header performs the requested method if the cached tags differ from the tags in the server’s document.
若server回复的报头中存在“Last-Modified”,那么客户端一定要在下一次请求报头中包含“If-Modified-Since”,所以说,这两个头部是相互对应的。那么当服务器收到客户端回复的“If-Modified-Since”头部之后会如何处理呢?首先服务器通过比较这两个时间,若“Last-Modified”更大,表明客户端缓存中的内容已经过时,此时server会将最新的文档(附上新的Header)返回客户端,并且状态码为200;否则认为客户端缓存中的内容仍然是最新的,只需向客户端返回304状态码,同时包含最新的HTTP头部。下面比较形象的显示了这两种处理情况。
可以明显的看出,“If-Modified-Since”实现重验证主要是通过比较时间来完成的,但是在某种情况下,它并不能十分奏效:
(1)服务器上的文档被后台周期性的重写,此时虽然日期发生变化,但是内容却没有发生任何变化。
(2)虽然服务器上的内容发生改变,但是却只是一些不太重要的信息,比如拼写错误等等,这样就导致文档在客户端重载,显然开销过大。
(3)一些web服务器上很难精确计算出文档的修改日期
(4)对于实时系统而言(文档修改很难再很短的时间内完成),显然也显得无能为力。
基于以上几点,HTTP规范定义了另外一种方式,即比较文档标签(Entity tags,Etags),它的基本思想是为每一个文档生成一个Etag,它可以是某个序列号,版本号或者检验。同样“If-None-Match”头部是与server端的“Etag”头部是相对应的,这样的server端只需要比较标签号就可以判断出客户端缓存中的文档是否是最新的。其处理方式与"If-Modified-Since"类似,下图是服务器与客户端的一种交互情况:
HTTP规范中定义了服务器如何约束、限制客户端缓存的头部,按照优先级分别有:
cache-control:no-store
cache-control:no-cache
cache-control:must-revalidate
cache-control:max-age
Expires
(1) no-store,no-cache头
"no-store"头是用来禁止客户端缓存来自于server的回复。当客户端收到来自于server的回复之后,客户端缓存一边将回复转发给客户端,随后进行删除。
"no-cache"头却不能阻止客户端将来自于server的回复缓存于本地,但是它限制本地cache不能在没有与远端server执行一致性检查的前提下直接响应用户。
【注意】从字面意思来讲,的确前者更加苛刻,然而不同的浏览器在具体实现时,却可能表现出不一样的行为。比如当IE浏览器收到“no-cache”头部的回复之后,它会一直与远端server做一致性检查;然而Firefox则不是这样,“no-cache”头部对它毫无作用,直接从缓存中响应用户请求,但是“no-store”头部却能起到相应的作用,因此,为了达到禁止本地缓存的目的,同时又要兼顾到浏览器的差异,server端应该同时回复“no-cache”和“no-store”头部。另外为了与HTTP/1.0兼容,需要加上“Pragma: no-cache”头部。
(2) must-revalidate头
“must-revalidate”头是为了要求缓存在响应用户请求之前一定要先保证缓存中的文档副本是最新的。
(3) max-age与Expires头
二者均是为了定义文档的过期时间,在客户端处理时,“max-age”均有更高的优先级,若max-age=0,则表示不能缓存文档或者每次访问缓存时前必须执行一致性检查。
上图很好地总结了不同浏览器的反映情况,如对于Firefox,当执行F5时,会触发浏览器发出“If-Modified-Since”和“Cache-Control:max-age=0”头部的发送,当然这些都不是绝对的,例如当本地缓存为空时,如去执行F5,其实作用类似于Ctrl+F5。