1、使用期和新鲜生存期
为了分辨已缓存文档是否足够新鲜,缓存只需要计算两个值:已缓存副本的使用期(age)和已缓存副本的新鲜生存期(freshness lifetime)。如果已缓存副本的时长小于新鲜生存期,就说明副本足够新鲜,可以使用。用Perl表示为:
$is_refresh_enough=($age<$freshness_lifetime);
文档的使用期是自从服务器将其发送出来(或者最后一次被服务器再验证)之后“老去”的总时间。缓存可能不知道文档响应是来自上游缓存,还是来自服务器,所以它不能假设文档是最新的。它必须根据显示的Age首部(优先),或者通过对服务器生成的Date首部的处理,来确定文档的使用期。
文档的新鲜生存期表明,已缓存副本在经过多长时间之后,就会因为新鲜度不足而无法再向客户端提供来。新鲜生存期考虑了文档的过期日期,以及客户端可能请求的任何新鲜度覆盖范围。
有些客户端可能愿意接受稍微有些过期的文档(使用Cache-Control:max-stale首部)。有些客户端可能无法接受会在近期过期的文档(使用Cache-Control:min-fresh首部)。缓存将服务器过期信息与客户端的新鲜度要求结合在一起,已确定最大的新鲜生存期。
2、使用期的计算
响应的使用期就是服务器发布响应(或服务器对其在验证)之后经过的总时间。使用期包含了在因特网路由器和网关中游荡的时间,在中间节点缓存中存储的时间,以及响应在你的缓存中停留的时间。
Http使用期计算的细节有点棘手,但其基本概念很简单。响应到达缓存时,缓存可以通过查看Date首部或Age首部来进行判断响应已使用的时间。缓存还能记录下文档在本地缓存中停留的时间。把这些都加起来,就是响应的总使用期。Http用一些魔法对时钟偏差和网络延时进行来补偿,但基本计算非常简单:
$age=$age_when_document_arrived_at_our_cache+$how_long_copy_has_been_in_out_cache
缓存可以很方便地判断出缓存副本已经在本地缓存来多长时间(这就是简单的笔记问题),但是很难确定响应抵达缓存时的使用期,因为不是所有的服务器的时钟都是同步的,而且我们也不知道响应到过那里。完善的使用期计算算法会试着对此进行补偿。
2.1 表面使用期是基于Date首部的
如果所有的计算机都是共享同样的、完全精确的时钟、已缓存文档的使用期就是文档的“表面使用期”--当前时间减去服务器发送文档的时间。服务器发送时间就是Date首部的值。最简单的起始时间计算可以直接使用表面时间:
$apparent_age=$time_got_response-$Date_header_value;
$age_when_document_arrived_at_our_cache=$apparent_age;
但并不是所有的时钟都实现来良好的同步。客户端和服务器时钟之间可能有数分钟的差别,如果时钟没有设置好的话,甚至会有数小时或者数天的区别。
Web应用程序,尤其是缓存代理,要做好与时间值有很大差异的服务器进行交互的准备。这种问题称为时钟偏差(clock skew)--两台计算机时钟设置的不同。由于时钟偏差的存在,表面使用期有时不太准确,而且有时会是负的。
如果使用期是负的,就将其设置为0.我们还可以对表面使用期进行完整性检查,一确定它没有大的令人不可思议,不过,实际上,表面使用期可能没有错。我们可能在与一个将文档缓存来很久的父缓存对话(缓存可能还存储来原始的Date首部)。
$apparent_age=max(0,$time_got_response-$Date_header_value);
$age_when_document_arrived_at_out_cache=$apparent_age;
要明确Date首部描述的是原始服务器的日期。代理和缓存一定不能修改这个日期!
2.2 逐跳使用期的计算
这样就可以去除时钟偏差造成的负数使用期来,但对时钟偏差给精确性带来的整体偏差,我们能做的工作很少。文档经过代理和缓存时,Http/1.1会让每台设备都将相对使用期累加到Age首部中,一次来解决缺乏通过同步时钟的问题。这种方式并不需要进行跨服务器的、端到端的时钟对比。
文档经过代理时,Age首部值会随之增加。使用Http/1.1的应用程序就应该在Age首部值中加上文档在每个应用程序和网络传输过程中停留时间。每个中间应用程序都可以很容易地使用本地时钟计算出文档的停留时间。
但响应链中所有的非Http/1.1设备都无法识别Age首部,它们会将首部未经修改地转发出去,或者将其删除掉。因此,在Htt/1.1得到普遍应用之前,Age首部都将是低估了相对使用期。
除了基于Date计算出来的Age之前,还使用了相对Age值,而且不论是跨服务器的Date值,还是计算出来的Age值都可能被低估,所以会选择使用估计出的两个Age值中最保守的那个(最保守的值就是最老的Age值)。使用这种方式,Http就能容忍Age首部存在的错误,尽管这样可能会搞错究竟哪边更加新鲜:
$apparent_age=max(0,$time_got_response-$Date_header_value);
$corrected_apparent_age=max($apparent_age,$Age_header_value);
$age_when_document_arrived_at_out_cache=$corrected_apparent_age;
2.3 对网络时延的补偿
事务处理可能会很慢。这是使用缓存的主要原因。但对速度非常慢的网络,或者那些过载的服务器来说,如果文档在网络或服务器中阻塞来很长时间,相对使用期计算可能会极大地低估文档的使用期。
Date首部说明文档是什么时候离开原始服务器的,但并没有说明文档在到缓存的传输过程中话费来多长时间。如果文档的传输经过来一长串的代理和父缓存,网络时延可能会相当大。
没有说明简单的方法可以用来测量到缓存的单向网络时延,但往返时延则比较容易测量。缓存知道它请求文档的时间,以及文档抵达的时间。http/1.1会在这些网络时延上加上整个往返时延,以便对其进行保守地校正。这个从缓存到服务器再到缓存的时延高估来从服务器到缓存的时延,但它是保守的。如果出错来,它会使文档比实际使用期要老,并引发不必要的再验证。计算是这样进行的:
$apparent_age=max(0,$time_got_response-$Date_header_value);
$corrected_apparent_age=max($apparent_age,$Age_header_value);
$response_delay_estimate=($time_got_response-$time_issued_request);
$age_when_document_arrived_at_out_cache=$corrected_apparent_age+$response_delay_estimate;
3、完整的使用期计算算法
上一节说明来当Http所承载的文档到达缓存时,如何计算其使用期。只要将这条响应存储到缓存中去,它就会进一步老化。当对缓存中文档的请求到达时,我们需要知道文档在缓存中停留来多长时间,只要才能计算文档的使用期:
$age=$age_when_document_arrived_at_out_cache+$how_long_copy_has_been_in_out_cache;
网友评论