HTTP权威指南--第7章 缓存

Web缓存是可以自动保存常见文档副本的HTTP设备。当一个请求到达缓存时,如果本地已有“已缓存的”有效副本可用,就可以直接从缓存返回响应。缓存具有以下优点:
1.减少了冗余的数据传输,节省了网络费用。
2.缓解了网络瓶颈的问题。不需要更多的带宽就能更快地加载页面。
3.降低了对原始服务器的要求。服务器可以更快地响应,避免过载的出现。
4.降低了距离时延,因为从较远的地方加载页面会更慢一些。

7.1 冗余的数据传输

当很多客户端访问一个流行的服务器时,服务器会多次传输同一份文档,这会造成数据传输冗余。

7.2 带宽瓶颈

很多网络为本地网络客户端提供的带宽比为远程网络提供的带宽要宽,本地缓存有数据的话,客户端就不需要和远程服务器进行数据传输,从而利用本地网络更宽的带宽进行数据传输。

7.3 瞬间拥塞

出现突发事件比如双十二等,很多人同时访问服务器可能会造成流量峰值是web服务器产生灾难性的崩溃。

7.4 距离时延

每台网络路由器都会增加因特网流量的时延。即使客户端和服务器之间没有太多的路由器,光速自身也会造成显著的时延。比如页面里包含很多小图片时(20张),而并行连接数量有限(4个),那么往返传输就会耗时较长。

7.5 命中和未命中的

缓存命中:可以用已有的副本为某些到达缓存的请求提供服务。
缓存未命中:其他一些请求可能会由于没有本地副本可用,而被转发给原始服务器。

7.5.1 再验证

就是验证本地缓存和服务器中的数据是否一致,保持更新。这种“新鲜度检测”被称为HTTP再验证。为了进行再验证,HTTP定义了一些特殊的请求,不用从服务器上获取整个对象,就可以快速检测出内容是否是最新的。
缓存对缓存副本进行再验证时,会向原始服务器发送一个小的再验证请求。如果内容没有变化,服务器会以一个小的304 Not Modified进行响应。缓存知道副本有效就会再次标识副本为新鲜的,并将副本提供给客户端,这被称为再验证命中(revalidate hit)或缓慢命中。因为经过了再验证步骤,所以比直接命中要慢一些。
HTTP提供的对缓存进行再验证的工具:
If-Modified-Since首部,服务器收到带有这个的请求可能有以下动作:
1.再验证命中:服务器发送HTTP 304 Not Modified响应。
2.再验证未命中:服务器会发送一个新的内容,HTTP 200 OK。
3.对象被删除:服务器已经把缓存对象删除,缓存收到后也会删除本地副本。

7.5.2 命中率

缓存命中率或文档命中率:由缓存提供服务的请求所占的比例。

7.5.3 字节命中率

由于文档大小不一,缓存提供的字节在传输的所有字节中所占的比例。

7.5.4 区分命中和未命中的情况

不幸的是,HTTP没有为用户提供一种手段来区分响应是缓存命中的,还是访问原始服务器得到的。客户端可以使用Date首部与当前时间进行比较判断一下是不是缓存的对象。

7.6 缓存的拓扑结构

私有缓存:单个用户专有的缓存。
公有缓存:大量用户共享的。

7.6.1 私有缓存

比如浏览器会将副本缓存到内存或磁盘。

7.6.2 共有代理缓存

公有缓存是特殊的共享代理服务器,被称为缓存代理服务器(caching proxy server),或者更常见的被称为代理缓存(proxy cache)。代理缓存会从本地缓存中提供文档,或者代表用户与服务器进行联系。可以接受来自多个用户的访问,所以可以更好滴减少冗余流量。

7.6.3 代理缓存的层次结构

在实际中,实现层次化(hierarchy)的缓存是很有意义的,就像内存的三级缓存或多级缓存一样。较小缓存未命中的请求会被导向较大的父缓存(parent cache),由它来为那些“提炼过的”流量提供服务。基本思想是在靠近客户端的地方使用小型廉价缓存,而更高层次中,则逐步采用更大、功能更强的缓存来装载多用户共享的文档。

7.6.4 网状缓存、内容路由以及对等缓存

网状缓存:是较复杂的结构而不是简单地缓存层次结构。网状缓存中的代理缓存之间会以更加复杂的方式进行对话,做出动态的缓存决策。这种代理缓存会决定选择何种路由对内容进行访问、管理和传送,因此可以将其称为内容路由器(content router)。
网状缓存中为内容路由设计的缓存要完成下列所有功能:
1.根据URL在父缓存或原始服务器之间进行动态选择。
2.根据URL动态地选择一个特定的父缓存。
3.前往父缓存之前,在本地缓存中搜索已缓存的副本。
4.允许其它缓存对其缓存的部分内容进行访问,但不允许因特网流量通过它们的缓存。

缓存之间这些更为复杂的关系允许不同的组织互为对等(peer)实体。

缓存的处理步骤

对一条HTTP GET报文的基本缓存处理过程包括7个步骤:
1.接受
2.解析
3.查询
4.新鲜度检测
5.创建响应
6.发送
7.日志

7.7.1 接收

缓存检测到一条网络连接上的活动,读取输入数据。高性能的缓存会同时从多条连接上读取数据,在整条报文抵达之前开始对事务进行处理。

7.7.2 解析

缓存将请求报文解析为片段,将首部的各个部分放入易于操作的数据结构中,这样,缓存软件就更容易处理首部字段并修改它们了。

7.7.3 查找

缓存获取了URL,查找本地副本。
已缓存的对象中包含了服务器响应主体和原始服务器响应首部。可能还包含一些元数据(metadata),用来记录在缓存中停留了多长时间,以及它被用过多少次等。

7.7.4 新鲜度检测

如果缓存停留时间较长,超过了文档的“新鲜度限制”(freshness limit),缓存需要与服务器进行确认。
如何进行新鲜度检测是一个大问题,本章很多内容讲的就是这个。

7.7.5 创建响应

缓存可能会对响应首部进行改造,以便与客户端的要求相匹配。比如将HTTP/1.0响应转换成HTTP/1,1响应。插入新鲜度信息(Cache-Control、Age以及Expires首部)等。
Date首部不应该被调整,它表示原始服务器对这个最初响应产生的日期。

7.7.6 发送

就是发送给客户端

7.7.7 日志

会保存一些与缓存的使用的统计数据,如命中和未命中

7.7.8 缓存处理流程图

7.8 保持副本的新鲜

HTTP有一些简单的机制可以在不要求服务器记住有哪些缓存拥有其文档副本的情况下,保持缓存与服务器数据之间的充分一致。

7.8.1 文档过期

通过特殊的HTTP Cache-Control 首部和Expires首部,HTTP让原始服务器向每一个文档附加一个“过期日期”。
在缓存文档过期之前,可以不进行新鲜度检测,除非客户端要求这么做,比如刷新页面。如果过期了,缓存要和服务器进行核对。

7.8.2 过期日期和使用期

服务器用HTTP/1.0+的Expires首部或者HTTP/1.1的Cache-Control: max-age响应首部来指定过期日期。Cache-Control首部使用相对时间而不是绝对日期,可以更好地解决各个机器之间时间不一致的问题。

7.8.3 服务器再验证

文档过期了不一定服务器上的文档进行了修改,只是意味着要进行核对的时间了。
HTTP协议要求行为正确的缓存返回下列内容之一:
1.“足够新鲜”的已缓存副本;
2.与服务器经过再验证,确认其仍然新鲜的已缓存副本。
3.如果需要与之进行再验证的原始服务器已经出故障,就返回一条错误报文。
4.附有警告信息说明内容可能不正确的已缓存副本。

7.8.4 用条件方法进行再验证

通过发送条件GET请求,将新鲜度检测和对象获取结合成了单个条件GET。
对缓存再验证来说最有用的两个首部是:
If-Modified-Since:如果从指定日期之后文档被修改了
If-None-Match:服务器可以为文档提供特殊的标签(参见ETag),而不是将其与最近修改日期相匹配,这些标签就像序列号一样。

7.8.5 If-Modified-Since:Date再验证

如果自指定日期后,文档被修改了,这个条件就满足,通常GET请求会成功执行。携带新首部的新文档会被返回给缓存。
如果没有被修改,条件就为假,会向客户端返回一个小的304 Not Modified响应报文,为了提高有效性,不会返回文档的主体。

7.8.6 If-None-Match:实体标签再验证

有些情况下使用最后修改日期再验证是不够的:
1.有些文档会被周期性地重写
2.有些文档可能被修改了,但做的修改不重要
3.有些服务器无法准确地判定其页面的最后修改日期
4.有些服务器提供的文档会在亚秒间隙发生变化
实体标签是附加到文档上的任意标签(引用字符串)。可以作为文档的指纹信息。
当发布者修改文档时,可以修改文档实体标签来说明这个新的版本。这样,如果实体标签被修改了,缓存就可以用If-None-Match条件首部来GET文档的新副本了。

7.8.7 强弱验证器

实体标签和最近修改日期都是缓存验证器(cache validator)
有时,服务器希望对文档进行一些非实质性或不重要的修改,不要使所有已缓存副本失效。HTTP/1.1支持“弱验证器”,如果只对内容进行了少量修改,就允许服务器声明那是“足够好”的等价体。
因此,存在弱实体标签强实体标签

7.8.8 什么时候应该使用实体标签和最近修改日期

如果服务器回送了一个实体标签,HTTP/1.1客户端就必须使用使用实体标签验证器。
如果服务器只回送了一个Last-Modified值,客户端就可以使用If-Modified-Since验证。
如果服务器两个都提供了,客户端应该使用这两种再验证方案。

7.9 控制缓存的能力

服务器可以通过HTTP定义的几种方式来指定在文档过期之前可以将其缓存多长时间。按照优先级递减的顺序,服务器可以:
1.附加一个Cache-Control:no-store首部到响应中去。
2.附加一个Cache-Control:no-cache首部到响应中去。
3.附加一个Cache-Control:must-revalidate首部到响应中去。
4.附加一个Cache-Control:max-age首部到响应中去。
5.附加一个Expires日期到响应中去。
6.不附加过期信息,让缓存确定自己的过期日期。

7.9.1 no-Store与no-Cache响应首部

这两个首部可以防止缓存提供未经证实的已缓存对象。
标识为no-store的响应会禁止缓存对响应进行复制。缓存会转发这个给客户端,然后删除对象。
标识为no-cache的响应实际上是可以存储在本地缓存区中的。只是在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用。

7.9.2 max-age响应首部

Cache-Control:mx-age首部表示的是从服务器将文档传来之时起,可以认为文档处于新鲜状态的秒数。

7.9.3 Expires响应首部

不推荐使用Expires首部,他指定的是实际的过期日期而不是秒数。

7.9.4 must-revalidate响应首部

这个首部告诉缓存,在事先没有跟原始服务器进行再验证的情况下,不能提供这个对象的陈旧副本。

7.9.5 试探性过期

如果响应中没有Cache-Control:max-age首部,也没有Expires首部,缓存可以计算出一个试探性最大使用期。可以使用任意算法。这个要特别小心,因为很难精确估计过期时间。

7.9.6 客户端的新鲜度限制

web浏览器都有Refresh(刷新)或Reload(重载)按钮,可以强制浏览器或代理缓存中可能过期的内容进行刷新。

7.9.7 注意事项

文档过期系统并不是一个完美的系统。数据不一致可能会出现。

7.10 设置缓存控制

不同的Web服务器为HTTP Cache-Control和Expirationsh首部的设置提供了一些不同的机制。本节简要介绍了Apache Web服务器是怎样的支持缓存控制的。

7.10.1 控制Apache的HTTP首部

Apache Web服务器提供了几种设置HTTP首部缓存控制的机制,其中很多机制在默认的情况下都没有启动—你要启动它们(有些情况下先要获取Apache的扩展模块)。
mod-headers模块:可以对单独的首部进行设置。

<Files * .html>
	Header set Cache-control no-cache
</Files>

上述设置将某个目录下所有HTML文档都标识为非缓存的。
mod_expires模块:提供的程序逻辑可以自动生成带有过期日期的Expires首部。
mod_cern_meta模块:可以将一个包含HTTP首部的文件与特定的对象联系起来。启动这个模块时,就创建了一组“元文件”,每个需要控制的文档一个,而且还会为每个元文件添加所期望的首部。

7.10.2 通过HTTP-EQUIV控制HTML缓存

为了让作者无需与Web服务器的配置文件进行交互的情况下,能够更容易地为所提供的HTML文档分配HTTP首部信息,HTML 2.0 定义了html<META HTTP-EQUIV>标签。这个可选的标签位于HTML文档的顶部,定义了与文档有所关联的HTTP首部。如:

<HTML>
	<HEAD>
		<TITLE>My Document</TITLE>
		<META HTTP-EQUIV="Cache-control" CONTENT="no-cache">
		</HEAD>
		...

上面代码表示这个HTML文档时非缓冲的。
但是这个标签不是控制文档缓存特性的好方法,服务器和代理不一定能很好地支持。通过配置正确的服务器发出HTTP首部,是传送文档缓存控制请求的唯一可靠方法。

7.11 详细算法(了解)

HTTP规范提供了一个详细,但又有点儿模糊不清且经常让人混淆的算法,来计算文档的使用期以及缓存的新鲜度。

7.11.1 使用期和新鲜生存期

7.12 缓存和广告

7.12.1 发布广告者的两难处境

缓存会向原始服务器隐藏实际的访问次数,如果缓存工作做得很好,原始服务器可能根本收不到任何HTTP访问,因为这些访问都被缓存吸收了。但如果你的收益是基于访问次数的话,你就高兴不起来了。

7.12.2 发布者的响应

现在,广告商会使用各种类型的“缓存清除”技术来确保缓存不会窃取他们的命中流量。比如加上no-cache首部、通过CGI网关提供广告或者在每次访问时重写广告URL。

一种更好的做法是:配置缓存,每次访问时都与原始服务器进行再验证。这样,每次访问时都会将命中推向原始服务器,但通常不会传输任何主体数据。当然,这样会降低事务处理的速度。

7.12.3 日志迁移

理想的解决方案是不需要将命中传递给服务器。毕竟,缓存就可以记录下所有的命中。缓存只要将命中日志发送给服务器就行了。

7.12.4 命中计数和使用限制

RFC2227 ,“HTTP的简单计数和使用限制”中定义了一种简单得多的方案。这个协议向HTTP中添加了一个成为Meter的首部,这个首部会周期性地将对特定URL的命中次数回送给服务器。通过这种方式,服务器可以从缓存周期性地获取对缓存文档的命中次数的更新。

而且,服务器还能控制在缓存必须向服务器汇报之前,其中的文档还可以使用多少次,或者为缓存文档设置一个时钟超时值。这种控制方式被称为使用限制;通过这种方式,服务器可以对缓存向原始服务器汇报之前,已缓存资源的使用次数进行控制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值