事先说明
标题说是“坑”,并没有说是“bug”,也就是多半是玩的姿势不对。
线上问题
我司(lecloud)目前线上大小文件都是使用的ATS 6.2.1版本,昨天运维反馈有文件超过缓存时间并不回源刷新,截图如下:
现象就是:age超过max-age了,过期了不更新!
另外需要说的一点就是,源站是可以正常回源的。
复现现象并打印调试日志
我复现了上述现象,发现问题的确如此,而且重启ATS之后,问题依旧。
这个问题,最本源的解决途径,就是去分析ATS对该请求的具体执行过程,特别是在判断缓存对象的refreshness这一块儿的判断细节。按照这个思路,我打开records.config中的debug选项,只过滤http.*相关的日志,traffic_line -x让配置生效后, 重新触发请求,得到了该请求完全的处理日志,我已经上传,参见下面的链接
https://download.csdn.net/download/tao_627/10845892
仔细分析该日志,与我最初的想法有些差异。我最初以为,这种情况下ATS回去回源校验,发现源站的内容没有变化,得到源站的304响应,然后还是将缓存中的内容返回给客户端,此时Age值继续增大。但是我仔细分析http请求的处理日志,发现并不是这样,ATS直接查缓存,并且校验缓存中的内容是refresh之后,就直接读取缓存并返回响应给客户端了。
那么这里值得怀疑的地方,就只能锁定在ATS对缓存object的refreshness的处理是否存在问题。
代码定位
从日志中的行号指示,主要定位到如下几个函数
注意这里
日志和代码一一对应上
可以看出,这里对缓存中一个document的freshness_limit的判断非常重要,优先考虑的是Cache-Control: s-maxage, 然后是max-age,如果没有这两个头,就再考虑Expires头,然后是Last-Modified/Date头,使用Last-Modified和Date头计算freshness_limit时,会用到下面的加权因子proxy.config.http.cache.heuristic_lm_factor,默认是0.10
freshness_limit = (date - last_modified) * 0.10
如果上面的http头都没有,直接使用配置值中的最小经验值proxy.config.http.cache.heuristic_min_lifetime
freshness_limit = s->txn_conf->cache_heuristic_min_lifetime
s-maxage与max-age的唯一区别是,s-maxage仅仅应用于共享缓存,而不应用于用户代理的本地缓存等针对单用户的缓存。另外,s-maxage的优先级要高于max-age.
上面的计算过程中,都使用到配置项proxy.config.http.cache.guaranteed_max_lifetime和proxy.config.http.cache.guaranteed_min_lifetime来限定一个缓存object的freshness_limit必须在这两者之间,默认配置情况下,也就是必须在一年以内。
CONFIG proxy.config.http.cache.guaranteed_max_lifetime INT 31536000
原因定位
ATS的官网文档
https://docs.trafficserver.apache.org/en/6.2.x/admin-guide/files/records.config.en.html
中有这个配置选项
proxy.config.http.cache.guaranteed_max_lifetime
默认配置是一年,在一年内会按照过期策略进行回源。 如果超过了, 在目前的配置下(恰好我们也是配置的1年)直接响应。在当前情况下,就会导致该资源永不过期。
解决方法
更新records.config文件,在末尾增加一行,将对象缓存时间最大设置为10年,或其它合适的值
CONFIG proxy.config.http.cache.guaranteed_max_lifetime INT 315360000
然后更新配置文件(不需要重启ats)
/usr/local/ats/bin/traffic_line -x
可见,还是我们对ATS 6.2.1的新特性不熟,导致掉进“坑”里了,属于玩的姿势不对。