squid中的時間和過期
引言:
Squid作为一个缓存工具,其核心的功能就是缓存。那么判断一个obj是否缓存以及缓存多久就是极为重要的工作。事实上目前我们SQUID开发的很多内容都是和这个问题有关。Squid在过期时间处理上有其独有的细致一面:不可避免的就会引入复杂的一面。理解squid就必须理解过期时间处理。这也是用好squid的一个前提。
1. squid过期相关的基础知识
1.1 概述
谈论squid就不得不谈论HTTP,谈论HTTP则必须提及RFC2616.
RFC2616文档(http1.1协议)定义了一系列的规则,我们需要就这些规则来指导我们的行为(也许跟据需求做相反的事情)。
HTTP缓存被定义为:除去许多情况下的对发送请求的需求,和除去在其他许多情况下发送完整响应的需求。前者需要控制不必要的网络奔波去下载不需要的东西,而后者是控制对不需要的东西仅请求不下载。这就牵扯到过期机制的两个组成方式:截止机制和验证机制。
截止机制:通俗说就是过期时间。HTTP缓存效率最大值的表现。如果一个资源(URI)仅仅从本地缓存目录中提取而产生响应无疑是最省力的。换句话说,缓存能够不必首先联系服务器而返回响应。
验证机制:和截止机制相关的。即在截止机制中设置了一个过期时间。当超过这个时间时,会收到一个带有验证请求的访问发往缓存而不是一个正常请求。如果缓存中的副本未有变化,则采用304Not Modified来说明此问题。否则必须回复完整响应(包含实体body)。
1.2 Date与 Expires
Date和Expires都是表示绝对时间的概念,其不同点在于:
Date给出的是响应发出的绝对时间。
格式为:
“Date:” HTTP-date |
Expires给出响应的内容过期的绝对时间。
格式为:
“Expires:” HTTP-date |
例如,今天是3月25日,apache源站设置了
ExpiresActive on ExpiresDefault “access plus 1 month” |
那么请求该源站返回的header中就应该包括
Expires: Fri, 24 Apr 2009 08:00:57 GMT |
注意:
a. Date与Expires都是绝对时间。
b. Date与Expires通常是格林尼治标准时间(如果后面带有GMT),也就是比北京时间早8个小时。
1.3 Age与max-age
这两个概念是比较容易搞混的。其相同点是:
a. 都是响应头的一部分
b. 都是一个时间长度,以秒为单位
但主要是不同点:
其中age是指:自从这个响应在源站服务器上生成以来(而不是源站内容修改以来!!),到现在所经历的秒数。
Age通常只对cache才有意义。
其格式为:
“Age:”age-value |
max-age是指:一个响应被源站发出后,在cache当中存活的时间,换句话说,一个响应的Age值如果超过了max-age,就认为这个响应是过期的。
当然,max-age也是对于cache才有意义。
其格式为:
“Cache-control: max-age=” max-age-value |
再次重申:max-age比Expires更加优先!
1.4 If-Modified-Since与Last-Modified
如果一个内容真的过期了,怎么办?从源站重新下载吗?
当然不。http协议对于过期的内容的处理,是先到源站验证一下,这个内容有没有发生改变,如果没有改变过,当然就不用重新下载了。这种验证是通过 If-Modified-Since等一系列http头实现的。
If-Modified-Since是http请求头的一部分,它表示客户端向源站询问“这个内容自从x年x月x日x时起,是否变过?”
其格式为:
“If-Modified-Since:” HTTP-date |
如果源站发现该内容变过,则会返回一个200OK的响应,并把新的内容发回来给客户端。
如果源站发现内容没有变过,则会返回一个304的响应,告诉客户端“没有改变过,你的内容还是可以用的”,这种情况下就不用发送内容了,可以大大节省传输带宽。
注意:
a)如果客户端发的If-Modified-Since后面的日期是非法的日期,源站将直接返回200OK+新内容。
b) If-Modified-Since后面跟的日期是客户端上一次接到的响应中,Last-Modified的值。
Last-Modified是响应头的一部分,是源站给出的,一个内容在源站上最终更新的时间。
对于静态内容,Last-Modified是文件的更新时间,对于动态内容,取决于源站的具体实现。
其格式为:
“Last-Modified:” HTTP-date |
1.5 Etag与If-None-Match
有的时候,Last-Modified 与 If-Modified-Since不能够可靠地标示内容的改变,这就需要Etag等更加可靠的打标签的机制。
Etag是响应头的一部分,是源站对内容所打的一个标签,用来标示这个文件,这个标签当且仅当内容变化才会变化,就像md5码一样。
与md5码不同的是,打Etag不需要读取整个文件的内容,比md5消耗的资源要少得多。
Etag起到的作用跟Last-Modified差不多,都是标示内容的变化,只是比Last-Modified更可靠。
If-None-Match是请求头的一部分,它表示客户端向源站询问“这个内容的标签还是不是xxxxxx?”
如果源站发现该内容变过,则会返回一个200OK的响应,并把新的内容发回来给客户端。
如果源站发现内容没有变过,则会返回一个304的响应,告诉客户端“没有改变过,你的内容还是可以用的”,这种情况下就不用发送内容了,可以大大节省传输带宽。
2. 目前过期时间部分我们的squid是如何实现(修改)的
2.1 squid碰到了什么困境
如上的squid描述我们可以看出squid在处理过期时间方面的支持是很强大也很全面的。但我们仍然发现一些因源站给出错误header导致我们缓存过期的问题(通常出现此问题即出现连续过期)。很多客户囿于技术/策略问题,将控制权交给我们。此时,我们就需要squid理顺过期关系进行自维护的处理。
2.2 mod_use_server_date做了什么
mod_use_server_date做的最重要的一件事情,就是确定一个obj的“起始”时间。知道一个obj从什么时候“出生”,然后知道其生存时间,即可完全决定其在squid的生存时间。第二件重要的事情就是“推定”经过其他squid设备的obj的“起始”时间。下面画图说明此问题:
如上图所示,在菱形时间点发生了请求,下层去获取OBJ进入squid群组和过期时间。
从上图我们可以发现其中核心功能实现是max-age(或者由expire和date计算得到)。而多层squid之间的交流主要靠AGE。也就是说:
Max-age(或者由expires-date计算得到)决定OBJ生存时长 Age决定OBJ的出生时间点 |
2.3 expires和refresh_pattern哪个在生效
如上(2.2节)是use_server_date的设计大意。那么在复杂的网络条件下,如何知道“是expires功能生效呢,还是refresh_pattern策略生效呢?”
要回答这个问题,首先要确认的是:
配置的refresh_pattern, URL对应行是否配置override-expire: 1)如果配置了,refresh_pattern生效,忽略过期时间 2)如果没有,先检查过期时间,再检查refresh_pattern |
目前我们的默认配置都是
ignore-reload 和override-lastmod(稍后讲解refresh_pattern时解释)所以可以不用注意如上问题。
如果确认如上refresh_pattern没有配置override-expire,则遵循如下规则:
如果源站给的信息可以计算出OBJ生存时间,则OBJ不走refresh_pattern 源站给的header可能: 1)有max_age 2)有expires和date 3)仅有expires 上述3者关系是顺序优先匹配,如果1符合就不需要2、3,同理2符合就不需要3. 满足此3项的为可计算生存时间的OBJ. |
有如上3个条件符合所得出的过期时间也不尽相同。
squid的处理策略,
如果源站给的Header符合:
1)有max_age
2)有expires和date
则结果相同,过期时间是squid最初服务时间+max-age或者是squid最初服务时间+源站expire-源站date。
如果源站给的Header符合:
3)仅有expires
则以此header数据为准,绝对时间设置过期。
3. 目前的refresh_pattern使用情况和存在问题
3.1 refresh_pattern概述
refresh_pattern是squid.conf中关于过期的一种配置项。
通常如下格式:
refresh_pattern -i ^http 1440 0% 1440 ignore-reload override-lastmod |
我们可以分解一行配置行为:
l 功能节名:refresh_pattern
l URL正则匹配区:-i ^http (-I含义为是否区分大小写)
l Age&lm-factore区:1440 0% 1440
l Options区:ignore-reload override-lastmod等
前二区目前没有疑问,下面就后二区详细介绍。
3.2 Age&lm-factore区
本区有3个配置节 分别为 min percentage max。
Min:是指一个object在缺少明确的Expires的情况下,能够确定的在cache中被认为新鲜的分钟数(小于此值肯定是新鲜的)。这个参数推荐设为0,否则会造成动态应用中的内容被不正确地缓存住。
Max:是指一个object在缺少明确的Expires的情况下,在 cache中可能被认为新鲜的分钟数的最大值(大于此值肯定是过期的)。
percentage是指,一个object在缺少明确的Expires的情况下,它的LM-factor的最大值(LM-factor超过此值则认为过期,否则新鲜)
LM-factor= (当前时间-到达cache的时间) / (到达cache的时间 – Last-Modified) * 100% |
关于LM-factor,在《Squid: The Definitive Guide》一书中,有一个更加形象的图来说明这个概念。
LM-factor是HTTP协议中关于Last-Modifed时间参与过期计算的一个模糊处理过期时间的方式(如果不指明某URL过期时间)。显然在我们目前的应用下,是不该使用此项模糊策略的。我们目前线上机器配置percentage为0%,已经省略此功能节。
3.2 Options区
我们squid使用squid2.7,其options区目前可以有:
- override-expire: 强制min在expires前生效。
- override-lastmod: 强制min在lm-factor之前生效(在expire之后)。
- reload-into-ims:将no-cache或者reload请求转化为IMS请求给源站。
- ignore-reload:将no-cache或者reload请求头忽略。
- ignore-no-cache:强制忽略从源站而来的“Pragma: no-cache”和“Cache-control: no-cache”
- ignore-private:强制忽略从源站而来的“Cache-control: private”
- ignore-auth:强制将一个请求认为是源站发送的带有“Cache-control: public”
- stale-while-revalidate=NN:强制在过期时间生效后的NN秒内非过期
- ignore-stale-while-revalidate:强制忽略源站带有的“Cache-Control: stale-while-revalidate=NN”header
- max-stale=NN:强制将一个超过NN秒的OBJ设置为未缓存,即使其在cache,或者更新失败。
- negative-ttl=NN:强制此行refresh_pattern的negative_ttl时间,即使全局已经有过期时间设置。
3. SQUID 304的修改
Squid如果缓存了一个OBJ,且其未过期时,如果碰到客户端来请求更新此obj,则squid向下发送的304/Not Modified中的header不能进行更新(特别是Date和Expires),还是给源站给的。此时会导致客户的IE中的date和expires 显示为很早之前的(上层一直缓存的)。 在这种情况下源站不发送过期时间靠我们refresh_pattern进行判断的话,则不能刷新客户端的缓存记录时间。
此问题虽然可以使用update_headers来规避,但是显然其开销是非常大的。SQUID 304修改可以在无损状态下修复此问题。对于关闭update_headers导致304较多或者源站未给明确过期时间的请求,修改后都可以看到很明显
目录 返回
首页