《HTTP权威指南》-第7章 缓存
7.1 冗余的数据传输
服务器会多次传输同一份文挡
7.2 带宽瓶颈
很多网络为本地网络客户端提供的带宽比为远程服务器提供的带宽要宽。
7.3 瞬间拥塞
瞬间访问量增大。
7.4 距离时延
7.5 命中和未命中的
这样看来缓存是有所帮助的。但缓存无法保存世界上每份文档的副本。
7.5.1 再验证
缓存对缓存的副本进行再验证肘,会向原始服务器发送一个小的再验证请求。如果内容没有变化,服务器会以一个小的304 Not Modified 进行响应。
HTTP 为我们提供了几个用来对已缓存对象进行再验证的工具,但最常用的是If-Modified-Since 首部。
7.5.2 命中率
命中文档比率。
对现在中等规模的Web 缓存来说, 40% 的命中率是很合理的。缓存的好处是,即使是中等规模的缓存,其所包含的常见文档也足以显著地提高性能、减少流量了。
7.5.3 字节命中率
字节命中比率。
7.5.4 区分命中和未命中的情况
有些商业代理缓存会在Via 首部附加一些额外信息,以描述缓存中发生的情况。
客户端有一种方怯可以判断响应是否来自缓存,就是使用Date 首部.将响应中Date 首部的值与当前时间进行比较,如果响应中的日期值比较早,客户端通常就可以认为这是一条援存的响应。客户端也可以通过Age 首部来检测缓存的响应,通过这个首部可以分辨出这条响应的使用期。
7.6.1 私有缓存
7.6.4 网状缓存、内容路由以及对等缓存
- 根据 URL 在父缓存或原始服务器之间进行动态选择。
- 根据URL 动态地选择一个特定的父缓存。
- 前往父缓存之前,在本地缓存中搜索已缓存的副本。
- 允许其他缓存对其缓存的部分内容进行访问,但不允许因特网流量通过它们的缓存。
HTTP 并不支持兄弟缓存, 所以入们通过一些协议对HTTP 进行了扩展,比如因特网缓存协议(Internet Cache Protocol, ICP)和超文本缓存协议(HyperText Caching Protocol, HTCP )。
7.7.1 第一步—-接收
缓存检测到一条网络连接上的活动,读取输入数据。高性能的缓存会同时从多条输入连接上读取数据,在整条报文抵达之前开始对事务进行处理。
7.7.2 第二步—-解析
缓存将请求报文解析为片断,将首部的各个部分放入易于操作的数据结构中。
7 .7.3 第三步—-查找
在第三步中, 缓存班取了URL,查找本地副本。
7.7.4 第四步—-新鲜度检测
HTTP 通过缓存将服务器文档的副本保留一段时间。在这段时间里,都认为文挡是“新鲜的”,缓存可以在不联系服务器的情况下,直接提供该文档。但一旦已缓存副本停留的时间太长,超过了文挡的新鲜度很值( freshness limit),就认为对象“过时”了,在提供该文档之前,缓存要再次与服务器进行确认,以查看文挡是否发生了变化。
7 .7 .5 第五步—-创建晌应
我们希望缓存的响应看起来就像来自原始服务器的一样,续存将已缓存的服务器响应首部作为响应首部的起点。然后缓存对这些基础首部进行了修改和扩充。
注意,缓存不应该调整Date 首部。Date 首部表示的是原始服务器最初产生这个对象的日期。
7.7.6 第六步—-发送
7.7.7 第七步—-日志
7.8 保持副本的新鲜
HTTP 有一些简单的机制可以在不要求服务器记住有哪些缓存拥有其文档副本的情况下,保持已缓存数据与服务器数据之间充分一致。HTTP 将这些简单的机制称为文档过期(document expiration)和服务器再验证(server revalidation)。
7.8.1 文档过期
通过特殊的HTTP Cache-Control 首部和Expires 首部, HTTP 让原始服务器向每个文档附加了一个“过期日期”。
在续存文档过期之前,缓存可以以任意频率使用这些副本,而无需与服务器联系—-当然,除非客户端请求中包含有阻止提供己缓存或未验证资源的首部。
7.8.2 过期日期和使用期
服务器用HTTTP/1.0+ 的Expires 首部或HTTP/1.1 的Cache-Control: max-age 响应首部来指定过期日期,同时还会带有响应主体。Expires 首部和Cache-Control:max-agye 首部所傲的事情本质上是一样的。但由于Cache-Control 首部使用的是相对时间而不是绝对日期, 所以我们更倾向于使用比较新的Cache-Control 首部。绝对日期依赖于计算机时钟的正确设置。
7.8.3 服务器再验证
仅仅是已缓存文档过期了并不意味着它和原始服务器上目前处于活跃状态的文档有实际的区别,这只是意味着到了要进行核对的时间了。这种情况被称为“服务器再验证”缓存需要询问原始服务器文档是否发生了变化。
- 再验证发现变化:缓存获取文档,更新本地缓存,返回给客户端。
- 再验证没有变化:缓存获取首部,包括一个新的过期日期,并对首部进行更新。
7.8.5 If-Modified-Since:Date再验证
- 如果自指定日期后,文档被修改了,If-Modif ied-Since 条件就为真,GET执行。新首部包含了一个新的过期日期。
- 如果自指定日期后,文档没被修改过,条件就为假,会向客户端返回一个小的304 Not Modified 响应报文。一般会发送一个新的过期日期。
7.8.6 If-None-Match : 实体标签再验证
- 有些文档可能会被周期性地重写(比如,从一个后台进程中写入),但实际包含的数据常常是一样的。尽管内容没有变化,但修改日期会发生变化。
- 有些文档可能被修改了。但所做修改并不重要,不需要让世界范围内的缓存都重装数据(比如对拼写或注释的修改)。
- 有些服务器无法准确地判定其页面的最后修改日期。
- 有些服务器提供的文档会在亚秒间隙发生变化(比如, 实时监视器),对这些服务器来说,以一秒为粒度的修改日期可能就不够用了。
7.8.7 强弱验证器
HTIP/1.1 支持“弱验证器”,如果只对内容进行了少量修改,就允许服务器声明那是“足够好”的等价体。
只要内容发生了变化,强验证器就会变化.弱验证器允许对一些内容进行修改,但内容的主要含义发生变化肘,通常它还是会变化的。有些操作不能用弱验证器来实现(比如有条件地获取部分内容),所以,服务器会用前缀“W/" 来标识弱验证器。
ETag: W/”v2.6”
If-None-Match: W/"v2.6"
7.8.8 什么时候应该使用实体标签和最近修改日期
如果服务器回送了一个实体标签, HTTP/1.1 客户端就必须使用实体标签验证器。如果服务器只回送了一个Last-Modified值,客户端就可以使用If-Modified-Since验证。如果实体标签和最后修改日期都提供了,客户端就应该使用这两种再验证方
方案,这样HTTP/1.0 和HTTP/1.1 缓存就都可以正确响应了。
除非HTTP/1.1 原始服务器无法生成实体标签验证器,否则就应该发送一个出去,如果使用弱实体标签有优势的话,发送的可能就是个弱实体标签,而不是强实体标签。
如果HTTP/1.1 缓存或服务器收到的请求既带有If-Modified-Since,又带有实体标签条件首部,那么只有这两个条件都满足肘,才能返回304 Not Modified 响应。
7.9 控制缓存的能力
服务器可以通过HTTP 定义的几种方式来指定在文档过期之前可以将其缓存多长时间。按照优先级递减的顺序,服务器可以:
- 附加一个Cache-Control: no-store 首部到响应中;
- 附加一个Cache-Control: no-cache 首都到响应中去;
- 附加一个cache-control: must-revalidate 首部到响应中去;
- 附加一个Cache -Control: max-age 首部到响应中去;
- 附加一个Expires 日期首部到响应中去;
- 不附加过期信息,让缓存确定自己的过期日期。
7 .9 .1 No-Store与No-Cache 响应首部
Pragma: no-cache
Cache-Control: no-store
Cache-Control: no-cache
标识为no-store 的响应会禁止缓存对响应进行复制。缓存通常会像非缓存代理服务器一样,向客户端转发一条no-store 响应,然后删除对象。
标识为no-cache 的响应实际上是可以存储在本地缓存区中的。只是在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用。
Pragma: no-cache
是为了兼容HTTP/1.0。HTTP/1.1应用程序应该使用Cache -Control : no- cache
。
7.9.2 max-age晌应首部
Cache-Control: max-age
首部表示的是从服务器将文档传来之时起,可以认为此文档处于新鲜状态的秒数。还有一个s-maxage
首部(注意maxage 的中间没有连字符),其行为与max-age
类似,但仅适用于共享(公有)缓存:
Cache-Control: max-age=3600
Cache-Control: s -maxage=3600
服务器可以请求缓存不要缓存文档,或者将最大使用期设置为零,从而在每次访问的时候都进行刷新:
Cache- control: max-age=O
Cache -Control: s-maxage=O
7.9.3 Expires 响应首部
不推荐使用Expires 首部,它指定的是实际的过期日期而不是秒数。
7.9.4 must-revalidate 响应首部
可以配置缓存,使其提供一些陈旧(过期)的对象,以提高性能。如果原始服务器希望缓存严格遵守过期信息,可以在原始响应中附加一个Cache - Control : must-revalidate
首部。
Cache-Control: must-revalidat e
如果在缓存进行must-revalidate 新鲜度检查时, 原始服务器不可用.缓存就必须返回一条504 Gateway Timeout
错误.
7.9.5 试探性过期
如果响应中没有Cache - Control: max-age
首部,也没有Expires 首部,缓存可以计算出一个试探性最大使用期。
可以使用任意算法,但如果得到的最大使用期大
于24 小时,就应该向响应首都添加一个Heuristic Expiration Warning (试探性过期警告,警告13 )首部。
LM-Factor 算站是一种很常用的试探性过期算怯, 如果文档中包含了最后修改日期,就可以使用这种算法。
- 如果已缓存文档最后一次修改发生在很久以前,它可能会是一份稳定的文档,不太会突然发生变化,因此将其继续保存在缓存中会比较安全。
- 如果已缓存文挡最近被修改过,就说明它很可能会频繁地发生变化,因此在与服务器进行再验证之前,只应该将其缓存很短一段时间。
7 .9.6 客户端的新鲜度限制
Web 浏览器都有Refresh (刷新)或Reload (重载)按钮。可以强制对浏览器或代理缓存中可能过期的内容进行刷新。Refresh 按钮会发布一个附加了Cache-Control 请求首部的GET 请求,这个请求会强制进行再验证,或者无条件地从服务器获取文挡。
7.9.7 注意事项
文挡过期系统并不是一个完美的系统。如果发布者不小心分配了一个很久之后的过期日期,在文挡过期之前,她要对文档做的所有修改都不会出现在任何缓存中。
7.10 设置缓存控制
7.10.1 控制Apache的HTTP首部
- mod headers
- mod_expires
- mod cem meta
7.10.2 通过HTTP, EQUIV控制HTML缓存
将HTML文档标记为非缓冲的:
<HTML> <HEAD> <TITLE >My Document</TITLE> <META HTTP-EQUIV="Cache-control" CONTENT="no-cache" /> </HEAD>
最初, HTTP-EQU工V 标签是给Web 服务器使用的。如HTML RFC 1866 所述, Web服务器应该为HTML 解析<META HTTP-EQUIV> 标签,并将规定的首部插入HTTP响应中:
不幸的是,支持这个可选特性会增加服务器的额外负载所以很少有Web 服务器和代理支持此特性。
有些浏览器确实会解析并在HTML 内容中使用HTTP-EQUIV 标签,像对待真的HTTP 首部那样来处理嵌入式首部。
这样的效果并不好,因为支持HTTP-EQUIV 标签的HTML 浏览器使用的Cache - control 规则可能会与拦截代理缓存所用的规则有所不同.这样会使缓存的过期处理行为发生混乱。
7.11 详细算法
7.11.1 使用期和新鲜生存期
7.11.2 使用期的计算
7.11.3 完整的使用期计算算法
7.11.4 新鲜生存期计算
7.11.5 完整的服务器—-新鲜度算法
7.12 缓存和广告
7 .12.1 发布广告者的两难处境
缓存可以让广告更快。
缓存减少广告到服务器的请求,减少收入。
7.12.2 发布者的响应
现在,广告商会使用各种类型的“缓存清除”技术来确保缓存不会窃取他们的命中流量。
这些缓存清除技术并不仅用于代理缓存。实际上,现在主要将其用于每个Web 浏览器中都启用了的缉存。但是,如果某些内容提供商维护其命中率的行为太过火了,就会降低缓存为其站点带来的积极作用。
一种解决方案就是配置缓存,每次访问时都与原始服务器进行再验证。这样,每次访问时都会将命中推向原始服务器,但通常不会传送任何主体数据。