Web缓存:
// 是可以自动保存常见文档副本的HTTP设备.
// 当Web请求抵达缓存时,如果本地有"已缓存的"副本,就可以从本地存储设备而不是原始服务器中提取这个文档.
冗余的数据传输:
// 有很多客户端访问一个流行的原始服务器页面时,服务器会多次传输同一份文档
// 每次传递给一个客户端.这样一些相同的字节会在网络中一遍遍的传输,大 大的降低了网络的传输效率,浪费Web资源.
// 有了缓存,就可以保留第一条服务器响应的副本.
带宽瓶颈:
// 很多网络为本地网络客户端提供的带宽比远程服务器提供的带宽要宽.因此提供缓存可以提供交互的速度
缓存未命中:
// 一些到达缓存的请求可能会由于没用副本可用,而被转发给原始服务器,称为缓存未命中.
再验证:
// 原始服务器的内容可能会发生变化,缓存要不时对其进行检测,看看它们保存的副本是否仍时服务器上最新的副本
// 这些"新鲜度检测"被称为HTTP再验证
再验证命中(缓慢命中):
// 缓存对缓存的副本进行再验证时,会向原始服务器发送一个小的在验证请求.如果内容没有变化
// 服务器会以一个小的304 Not Modified进行响应.
// 只要缓存知道副本仍然有效,就会再次将副本标识为暂时新鲜的,并将副本提供给客户端,这被称作在验证命中或缓慢命中
缓存命中率:
// 缓存提供服务的请求所占的比例称为缓存命中率
// 对中等规模的Web缓存来说,40%的命中率是很合理的
字节命中率:
// 缓存提供的字节在传输的所有字节中所占的比例
私有缓存:
// 私有缓存不需要很大的存储空间,这样可以做得很小很便宜.
// Web浏览器中有内建的私有缓存---大多数浏览器都会将常用文档缓存在个人电脑的磁盘和内存中,并且允许用户区配置缓存的大小和各种设置
公有代理缓存:
// 公有缓存是特殊的共享代理服务器,被称为缓存代理服务器(caching proxy server)或常见的代理缓存(proxy cache)
// 代理缓存会从本地缓存中提供文档,或者代表用户于服务器进行联系
内容路由器:
// 有些网络结构会构建复杂的网状缓存,网状缓存中的代理缓存之间会以更加复杂的方式进行对话,做出动态的缓存通信决策
// 决定与哪个父缓存进行对话,或者决定绕开缓存,直接连接原始服务器.这种代理缓存会决定选择何种路由器对内容进行访问、管理和传送
文档过期:
// HTTP有一些简单的机制可以再不要求服务器记住有哪些缓存拥有其文档副本的情况下,保持已缓存数据与服务器之间充分一致
// HTTP将之称为文档过期.// 文档过期(Expires首部)
HTTP/1.0 200 OK
Date: Sat, 29 Jun 2002, 14:30:00 GMT
Content-type: text/plain
Content-legnth: 67
Expires: Fri, 05 Jul 2002, 05:00:00 GMTIndependence Day sale at Joe`s Hardware Come shop with us today!// Cache-Control: max-age 首部 (最大的生存时间,单位:秒)
HTTP/1.0 200 OK
Date: Sat, 29 Jun 2002, 14:30:00 GMT
Content-type: text/plain
Content-length: 67
Cache-Control: max-age=484200Independence Day sale at Joe`s Hardware Come shop with us today!
服务器再验证:
// 仅仅是已缓存文档过期了并不意味着它和原始服务器上目前处于活跃状态的文档有实际区别;只是意味着到了要进行核对的时间了.
// 这种情况称为“服务器再验证”// If-Modified-Since:Date再验证
// 条件请求
GET /announce.html HTTP/1.0
If-Modified-Since: Sat, 29 Jun 2002, 14:30:00 GMT// 响应(成功的在验证)
HTTP/1.0 304 Not Modified
Date: Wed, 03 Jul 2002, 19:18:23 GMT
Expires: Fri, 05 Jul 2002, 14:30:00 GMT// 响应(失败的再验证)
HTTP/1.0 200 OK
Date: Fri, 05 Jul 2002, 17:54:40 GMT
Content-length: 124
Expires: Mon, 09 Sep 2002, 05:00:00 GMTAll exterior house paint on sale through Labor Day.
Just Another reason for you to shop this summer at Joe`s Hardware!// If-None-Match:实体标签再验证(再某些情况下,仅使用最后修改日期再验证是不够的)
// 条件请求
GET /announce.html HTTP/1.0
If-None-Match: "v2.6"// 响应
HTTP/1.0 304 Not Modified
Date: Wed, 03 Jul 2002, 19:18:23 GMT
ETag: "v2.6"
Expires: Fri, 05 Jul 2002, 05:00:00 GMT// 强弱验证器
// 有时服务器希望对文档进行一些非实质性或不重要的修改时,不要使所有的已缓存副本都失效,
// HTTP/1.1支持"弱验证器"
// 服务器会用"W/"来标识弱验证器
ETag: W/"v2.6"
If-None-Match: W/"v2.6"
no-Store与no-Cache响应首部
Pragma: no-cache
Cache-Control: no-store
Cache-Control: no-cache
// no-store:禁止缓存对响应进行复制
// no-cache的响应在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用
// 以上2种对象是HTTP/1.1提供的,为了兼容于HTTP/1.0+,使用了Pragma: no-cache
max-age:
Cache-Control: max-age=3600
Cache-Control: s-maxage=3600
// max-age 此文档处于新鲜状态的秒数
// s-maxage 此文档处于新鲜状态的秒数,但仅适用于共享(公有)缓存// 服务器请求缓存不缓存该文档:
Cache-Control: max-age=0
Cache-Control: s-maxage = 0
Expires:
Expires: Fri, 05 Jul 2002, 05:00:00 GMT
// 实际的过期日期
// 不推荐使用的原因:许多服务器的时钟都不同步,或者不正确,所以最好用剩余秒数
must-revalidate:
Cache-Control: must-revalidate
// 原始服务器希望缓存严格遵守过期信息
// 该响应首部告诉缓存,在事先没有跟原始服务器进行再验证的情况下,不能提供对这个对象的陈旧副本
试探性过期
// 如果响应种没有Cache-Control: max-age首部,也没有Expires首部,缓存可以计算出一个试探性最大使用期
// 如果得到的最大试用期大于24小时,就应该向响应首部添加一个Heuristic Expiration WarningLM-Factor算法:
// 逻辑:
// 如果已缓存文档最后一次修改发生在很久以前,它可能会是一份稳定的文档,不太会突然发生变化 ,因此将其继续保存在缓存中
// 如果已缓存文档近期被修改过,就说明它很可能会频繁发生变化,因此在与服务器进行再验证之前,只应该将其缓存很短一段时间
// 下面是LM-factor算法的Perl伪代码:
$time_since_modify = max(0, $server_Date - $server_Last_Modified);
$server_freshness_limit = int($time_since_modify * $lm_factor);
Apache关于缓存的HTTP首部
// mod_headers
// 将某目录下的所有HTML文件都标识为非缓存
<Files * .html>Header set Cache-control no-cache
</Files>// mode_expires
// 将文档的过期日期设置为对其最后一次被访问之后或者其最近修改日期之后的某一时间
// 可以为不同的文件类型设置不同的过期日期
ExpiresDefault A3600
ExpiresDefault M86400
ExpiresDefault "access plus 1 week"
ExpiresByType text/html "modification plus 2 days 6 hours 12 minutes"
通过HTTP-EQUIV控制HTML缓存
// 让coder无需与Web服务器的配置文件进行交互,能够更容易地为所提供地HTML文档分配HTTP首部信息
// HTML2.0 定义了 <META HTTP-EQUIV>标签
<HTML><HEAD><TITLE>My Document</TITLE><META HTTP-EQUIV="Cache-control" CONNECT="no-cache"></HEAD>...
</HTML>
新鲜度算法(服务器)
sub server_freshness_limit
{local($heuristic, $server_freshness_limit,$time_since_last_modify);$heuristic = 0;if ($Max_Age_value_set) {$server_freshness_limit = $Max_Age_value;} else if ($Expires_value_set) {$server_freshness_limit = $Expires_value - $Date_value;} else if($Last_Modified_value_set) {$time_since_last_modify = max(0, $Date_value - $Last_Modified_value);$server_freshness_limit = int($time_since_last_modify * $lm_factor);$heuristic = 1;} else{$server_freshness_limit = $default_cache_min_lifetime;$heuristic = 1;}if($heuristic) {if($server_freshness_limit > $default_cache_max_lifetime) {$server_freshness_limit = $default_cache_max_lifetime;}if( $server_freshness_limit < $default_cache_min_lifetime) {$server_freshness_limit = $default_cache_min_lifetime;}return ($server_freshness_limit);}
}
新鲜度算法(客户端)
sub client_modified_freshness_limit
{$age_limit = server_freshness_limit();if($Max_Stale_value_set) {if( $Max_Stale_value == $INT_MAX){$age_limit = $INT_MAX;} else{$age_limit = server_freshness_limit() + $Max_Stale_value;}}if( $Min_Fresh_value_set) {$get_limit = min($age_limit, server_freshness_limit() - $Min_Fresh_value_set);}if($Max_Age_value_set) {$age_limit = min($age_limit, $Max_Age_value);}
}
参考 《HTTP权威指南》第7章