http://blog.chinaunix.net/uid-8474831-id-3480633.html
今天要说的话题是refresh_pattern,是网上有很多人写过了的。比如这个
refresh_pattern 的算法如下:(当前时间定义为CURRENT_DATE) |
这个
· 如果有定义refresh_pattern:只要满足以下两个条件之一,缓冲对象过期 · 缓冲对象在squid的cache缓冲的时间大于refresh_pattern定义的max · 缓冲对象在squid的cache缓冲的时间大于(原始数据进入squid的缓冲的时间-原始web数据所规定的Last-Modified时间)*percent · 如果符合多个refresh_pattern定义,以第一条符合定义的refresh_pattern为准 · 如果没有符合定义的refresh_pattern,则按squid的默认处理规则
|
还有这个
FRESH if (CURRENT_DATE – DATE) < min FRESH if (CURRENT_DATE – DATE)/(DATE – LM_DATE) < percent STABLE if (CURRENT_DATE – DATE) > max OTHER, STABLE
|
等等。
其中有一些是相互矛盾的,有一些没把refresh_pattern的全部选项说清楚,还有refresh_pattern在miss时所起的作用很少有人说。
今天我就对照着代码,把refresh_pattern的所有作用,以及squid的过期校验机制全都讲一遍。
1. 先说说refresh_pattern最主要的作用,过期校验。
Squid的过期校验是访问驱动的,如果一个object过期了,却又一直没人访问,那么squid会一直把这个object扔在那里,而不会主动地回源校验它。只有当客户端访问到了这个object的时候,squid才会校验。这样做的原因也不难理解,如果一个object总是不被访问到,就没有必要为了校验它浪费宝贵的cpu和回源带宽资源,等到有人访问它时再校验也不迟。
回源校验的流程发起在
clientProcessRequest ->storeClientCopy ->clientCacheHit ->refreshCheckHTTPStale(const StoreEntry * entry, request_t * request) -> refreshCheck (const StoreEntry * entry, request_t * request, time_t delta)
|
从clientCacheHit往上,都是squid处理客户端请求的代码。从refreshCheckHTTPStale往下,就都是squid专门用来检查过期的函数了。简单地说,就是把请求扔进refreshCheckHTTPStale,然后结果返回给clientCacheHit,然后根据结果来决定是继续HIT还是转到过期流程。
refreshCheckHTTPStale的返回值很有意思,有这么几种:
-1,-2,0,1,3
0是最普遍的,表示未过期。
-1表示stale_hit,也就是过期程度在配置文件的refresh_stale_hit选项规定的范围内,这种情况也算命中。
-2表示stale-while-revalidate生效了。这是squid先给出旧内容到客户端,然后异步地回源校验,校验完成前都会给旧内容
1 表示普通的过期
3表示这个object的过期程度已经大于配置文件中的max_stale所规定的范围,必须回源校验了。这里,返回值1和3的处理方式是一样的。
refreshCheckHTTPStale与refreshCheck共同作用,得到上述的几种返回值。首先,通过refresh_pattern或者原站reply的Date头,Expires头和Cache-Control头得到一个staleness,这个staleness代表这个object的过期程度,然后再经过一系列计算,最终得到我们需要的返回值。
这里要先介绍一下refresh_pattern的配置方法:
refresh_pattern [-i] regex min percent max [options] -i表示正则匹配时不区分大小写 regex是与url进行匹配的正则表达式 min,percent,max 是3个数字,后面会介绍到用处 options是refresh_pattern的其他选项,包括以下几种 override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private ignore-auth stale-while-revalidate=NN ignore-stale-while-revalidate max-stale=NN negative-ttl=NN 作用会在后面介绍
在所有的refresh_pattern中,从上往下数,第一个与当前请求url匹配的就会作用于过期判断过程。后面称为“匹配的refresh_pattern”
|
首先是得到staleness的过程
上面的图看起来有点复杂其实就是,staleness=-1的,表示未过期,其他都是过期了。
然后用这个staleness,加上refresh_pattern中的各种参数,最终得出refreshCheckHTTPStale的结果
上面这个图,就是网上流传甚广的refresh_pattern的说明,其实过期的判断在后面还有很多步骤。但所谓的“refresh_pattern各种参数”并不是非常常见,所以只想了解min,percent,max的人看到这里就可以结束了。
============================割了割了=========================
接下来这张图,是refresh_pattern的其他选项与staleness共同作用,对过期判断的影响
2. 可缓存与否的判断
refresh_pattern在过期判断时的作用已经说完了。接下来说说在miss的时候refresh_pattern起到的作用。
Miss的时候,一个object的header部分被squid得到之后,是要判断一下,这个object在过期校验层面上,是否适合被缓存。如果不适合,将直接不缓存这个object。
判断的过程在
httpCachableReply ->refreshIsCachable ->refreshCheck
|
refreshIsCachable会返回0或者1,1表示这个object在过期校验的层面上是可以被缓存的(当然,还需要其他层面也可以缓存才会真正存下来)。而它的核心功能仍然是refreshCheck,只是这次调用refreshCheck的时候,先假定一个delta秒之后的时间为当前时间,再进行refreshCheck的过程(求staleness,然后用refresh_pattern进行修正。参见上面画的2张流程图)。这个delta的取值,正是配置文件中的minimum_expiry_time这个配置项(未配置的情况下默认为60秒),这个选项的意思是,过期时间必须大于多少秒方可缓存。假如minimum_expiry_time=60,并且(原站给出的Expires头是在50秒后,或者Cache-Control:max-age=50),那么这个object将被认为要在50秒后过期,小于不能被缓存。
假如refreshCheck的返回在minimum_expiry_time这段时间之后,object并不过期的话,refreshIsCachable还要检查一件事,就是这个object到底能否被校验。我们知道,要校验一个object主要有2种手段,If-Modified-Since和If-None-Match,一个需要Last-Modified头,一个需要ETag头。这两个头如果都没有的话,object也是不能缓存的。
用流程图来描述,就是
3. 校验失败时能否给出旧内容的判断
以上两处,是refresh_pattern相对常用的功能,还有一处稍微冷僻的用处,就是检查当回源校验失败时,是否能将已经过期的object给出去。如果一次回源校验,原站给出了一个5xx的话,squid为了能让客户端继续拿到内容,可能会将磁盘上的旧内容发给客户端,但要有一定的条件,即检查object是否已经“严重过期”。这个判断在
clientHandleIMSReply ->clientGetsOldEntry ->refreshCheckStaleOK ->refreshCheck |
如果通过检查refreshCheck,发现原站给出的reply里面没有要求Cache-Control:must-revalidate,并且没有走到让refreshCheckHTTPStale返回3的那两个分支的话(也就是过期时间在max-stale之内),就可以考虑继续给出旧内容。这里逻辑相对简单,就不画图了。
上面反复提到的一个过程就是“过期校验”,这个过程也挺复杂,我们会在后面的博客里继续说明。