现代的商业化代理缓存相当的复杂。这些缓存构建的非常高效,可以支持HTTP和其他一些技术的各种高级特性。但除了一些微妙的细节之外,Web缓存的基本工作原理大多很简单。对一条HTTP GET报文的基本缓存处理过程包括7个步骤:
缓存检测到一条网络连接上的活动,读取输入数据。高性能的缓存会同时从多条输入连接上读取数据,在整条报文抵达之前开始对事务进行处理。
缓存将报文解析为片段,将首部的各个部分放入易于操作的数据结构中。这样缓存软件就更容易处理首部字段并修改他们了。
解析程序还要负责首部各部分的标准化,将大小写或者可替换数据格式之类不太重要的区别都看成等效的。
缓存获取URL后,查找本地副本。本地副本可能存储在内存,本地磁盘,甚至附近的另一台服务器中。专业级的缓存会使用快速算法来确定本地缓存中是否有某个对象。如果本地没有这个文档,他可以根据情形和配置,到原始服务器或父代理中去取,或者返回一条错误信息。
已缓存的对象中包含了服务器响应主体和原始服务器响应首部,这样就会在缓存命中时返回正确的服务器首部。已缓存的对象中还包含一些元数据(metadata),用来记录对象在缓存中停留了多长时间,以及它被用过多少次等。
HTTP通过缓存将服务器文档的副本保留一段时间。在这段时间里,都认为文档是”新鲜的”, 缓存可以在不联系服务器的情况下,直接提取该文档。但一旦已缓存副本停留的时间太长,超过了文档的新鲜度限值(freshness limit),就认为对象”过时”了,在提供该文档之前,缓存要再次与服务器进行确认,以查看文档是否发生了变化。客户端发送给缓存的所有请求首部自身都可以强制缓存进行再验证,或者完全避免验证,这使得事情变得更加的复杂。
HTTP有一组非常复杂的新鲜度检测规则,缓存产品支持的大量配置选项,以及与非HTTP新鲜度标准进行互通的需要则使得问题变得更加严重。
HTTP有一些简单的机制可以在不要求服务器记住有哪些缓存拥有其文档副本的情况下,保持已缓存数据与服务器数据之间充分一致。HTTP将这些简单的机制称为文档过期和服务器再认证。
通过特殊的HTTP Cache-Control首部(HTTP/1.0+)和Expires首部(Cache-Control),HTTP让原始服务器向每个文档附加了一个”过期时间”。在缓存文件过期之前,缓存可以以任意频率使用这些副本,而无需与服务器联系。
过期响应首部:
首部 | 描述 |
---|---|
Cache-Control: max-age | max-age值定义了文档的最大使用期——从第一次生成文档 到文档不再新鲜、无法使用为止,最大的合法生存时间。 Cache-Control: max-age=484200 |
Expires | 指定一个绝对的过期日期。如果过期日期已经过了,就说明 文档不再新鲜了 Expires: Fri, 05 Jul 2016, 05:00:00 GMT |
由于Cache-Control首部使用的是相对时间而不是绝对时间,所以我们更倾向于使用比较新的Cache-Control首部。绝对时间依赖于计算机时钟的正确设置。
仅仅是已缓存文档过期了并不意味着它与原始服务器上目前处于活跃状态的文档有实际的区别,这只是意味着到了要进行核对的时间了。这种情况被称为”服务器再验证”,说明缓存需要询问原始服务器文档是否发生了变化。
HTTP的条件方法可以高效地实现再验证。HTTP允许缓存向原始服务器一个”条件GET”, 请求服务器只有在文档和缓存中现有的副本不同时,才回送对象主体。通过这种方式,将新鲜度检测和对象获取结合成了单个条件GET。向GET请求报文中添加一些特殊的条件首部,就可以发起条件GET。
缓存再验证中使用的两个条件首部:
首部 | 描述 |
---|---|
If-Modified-Since: |
如果从指定日期之后文档被修改过了,就执行请求的方法 。可以与Last-Modified服务器响应首部配合使用,只有 在内容被修改后与已缓存版本有所不同的时候才去获取内容 |
If-None-Match: |
服务器可以为文档提供特殊的标签(ETag),而不是将其与 最近修改日期相匹配,这些标签就像序列号一样。如果已 缓存标签与服务器文档中的标签有所不同, If-None-Match首部就会执行所请求的方法 |
1. If-Modified-Since: Date 再验证(IMS请求)
有些情况下仅使用最后修改时间进行再验证是不够的。为了解决这些问题,HTTP允许用户对被称为实体标签(ETag)的”版本标识符”进行比较。实体标签是附加到文档上的任意标签(引用字符串)。它们可能包含了文档的序列号或版本号,或者是文档内容的检验和及其它指纹信息。
当发布者对文档进行修改时,可以修改文档的实体标签来说明这个新的版本。这样,如果实体标签被修改了,缓存就可以用If-None-Match条件来GET文档的新副本了。
我们希望缓存的响应看起来就像来自原始服务器的一样,缓存将已缓存的服务器响应首部作为响应首部的起点。然后缓存对这些基础首部进行了修改和扩充。
缓存负责对这些首部进行改造,以便与客户端的要求相匹配。注意,缓存不应该调整Date首部。Date首部表示的是原始服务器最初产生这个对象的时间。
一旦响应首部准备好了,缓存就将响应回送给客户端。和所有代理服务器一样,代理缓存要管理与客户端之间的连接。高性能的缓存会尽全力高效的发送数据,通常可以避免在本地缓存与网络I/O缓冲区之间进行文档内容的复制。
大多数缓存都会保存日志文件以及与缓存使用的一些统计数据。每个缓存事务结束之后,缓存都会更新缓存命中和未命中数目的统计数据(以及相关的度量值),并将条目插入一个用来显示请求类型、URL和所发生事件的日志文件。