本站文章(技术文章和tank手记)均为社长矢量比特工作.实践.学习中的心得原创,请勿转载!
/

抽象nginx做cache时缓存判断万能公式——存不存、存多久、用不用

CDN/Cache 矢量比特

Nginx/tengine(后面名称只写nginx了)单纯做cache性能比不过ats,特别是在磁盘处理方面,不过论综合能力nginx就是大拿了,他集web服务器、负载均衡、cache三种能力于一身,可以说是非常综合性的选手

Nginx是综合型的大拿选手,他集web服务器、负载均衡、cache三种能力于一身,可以说是无所不能。比如说一个中型网站的场景选型,前端是负载,后端托着一堆apache服务器,现在该到前端负载选型的了,虽然lvs和ha单纯从负载的性能要比nginx好一些,但我还是会选nginx,因为nginx在做负载的同时,可以将热点的静态内容cache一遍,做一次加速,无形间减轻了后端web服务器的压力,提高了用户体验,一箭双雕。Nginx做cache配置是很灵活的,里面有各种缓存指令,起初接触会摸不到北,不知道缓存怎么生效、怎么过期、怎么更新,用了一段时间后我终于抽象出了一套缓存判断的万能公式——存不存、存多久、用不用?

Nginx的资源是否缓存是由客户端、源站与nginx的缓存配置共同决定,nginx如果没有缓存策略配置,默认按照request请求头、header响应头信息走标准的http缓存判断机制(看cache-control、expires、cookie这些属性),仅当一个资源没有被设为不能缓存的黑名单,且有大于0的存放时间的生命周期时,资源才被缓存,对于nginx做cache时缓存判断的万能公式集成到一张图上如下,一个资源只有同时具备可缓存和有缓存时间大于0的缓存生命周期双重属性,才能真正被缓存下来,至于存下来之后用不用还得再进行下一步的判断

QQ图片20170411102334.png

存不存:如果没有设置,会根据源站响应头信息走标准的http协议缓存判断机制,查看cache-control、expires以及cookie等属性,nginx主要设置参数有:

proxy_ignore_headers X-Accel-Expires |Expires | Cache-Control |Set-Cookie)忽略这些header响应头属性的判断,是缓存的必要不充分条件。

proxy_no_cache ($cookie_nocache  $arg_nocache $arg_comment)如果任何一个变量参数值不为空,或者不等于0,nginx就不会对资源进行缓存,直接进行代理转发,是缓存的必要不充分条件。

存多久:如果一个资源没有被加入不能存的黑名单,也就是说这个资源是可以存的,然后就会到这个判断环节“存多久”,如果存多久的时间参数为0,那么这个资源也是不会存的,存多久有其优先级的判断顺序

1级、proxy_cache_pathinactive参数,意思是一个已存资源多久内一次访问也没有就将其删除,这个缓存时间优先于所有策略;

2级、响应头Expires属性,就是资源存到什么时候过期,这个是第二优先级策略,有这个属性后将停止后续的时间判断;

3级、响应头cache-control里的max-age,这个是第三优先级存多久的参数,如果有max-age将不再看后续的时间判断;

4级、 proxy_cache_valid 200 1d;默认的存储时间缓存策略,比如当前参数,如果一个200ok的资源是可以存的,但是没有其它策略说可以存多久,默认走的是这个参数的缓存时间,此参数设置是很灵活的,可以对各种状态码进行配置。

用不用:用不用有两种情况,一个是已经过期的资源用不用,另一个是没过期的资源用不用,日志打印有BYPASS、EXPIERD、STALE、UPDATING这些,具体如下:

proxy_cache_bypass ($cookie_nocache $arg_nocache$arg_comment)任何一个变量参数不为空,都直接回源,不考虑缓存中有没有,request头里面有nocache直接回源;

proxy_cache_use_stale(error timeout invalid_header updating http_500 http_502 http_503 http_504)发现已经缓存的内容有这些问题,直接用过期的缓存资源回复;

proxy_cache_revalidate off;如果一个走默认缓存时间的资源过期了,且当前参数是off,直接忽略缓存资源直接回源,日志EXPIERD。

 测试举例默认配置,一个200ok资源(http://www.haixiano.com/member/login.php)  只有cookie信息没有max-age。

第一次测试配置参数:

proxy_cache_valid 200 10m;
#proxy_ignore_headers Set-Cookie; 注释掉

头信息以及测试如下:

wKioL1cPbnayRC0JAAAsHoXTdhw133.png

多次访问操作如下:

wKiom1cPbm7TYRB_AABpzo-8Hb0722.png

多次访问日志如下(全部MISS):

wKiom1cPdxzTAO0OAACtDhgeoWQ438.png

小结:虽然有对于200ok的信息设置缓存时间为10分钟,但是cookie信息的首先判断是不能存,所以根本不会看你对200ok资源的缓存时间,最终结论是不能存。

第二次测试配置参数:

#proxy_cache_valid 200 10m;注释掉

proxy_ignore_headers Set-Cookie;

多次访问日志如下(全部MISS):

wKioL1cPd-jgaDnrAAD8HZBtfGw201.png

小结:虽然忽略了对cookie信息的判断,告诉nginx有cookie的信息是可以存的,但是对于200ok的信息设置缓存时间为0,所以最终资源还是不能存。

第三次测试配置参数:

proxy_cache_valid 200 10m;
proxy_ignore_headers Set-Cookie;

多次访问日志如下(1次访问MISS后,之后均为HIT):
wKiom1cPeL7A0f8QAAC6thsutOU785.png

小结:首先忽略了cookie信息的判断,告诉nginx说cookie信息是可以存的,后查询没有expires和max-age就去找默认缓存时间,发现对于200ok的默认缓存时间是10m,所以最终判定可以缓存,有效缓存时间为10分钟。

综上论证,一个资源只有同时具备可缓存和有缓存时间大于0的生命周期的双重属性,才能真正被缓存下来,至于存下来之后用不用还得再进行下一步的判断。所以nginx对于资源是否缓存要经过两步判断,第一步存不存,第二步存多久,对于是否用缓存了的资源为用户进行服务还得进行下一层用不用的判断,详细的走的判断参数可以看我画的那张图。

优化建议:为了做到cache加速的同时,又不影响业务,在缓存策略配置上最好遵循头部信息的要求,不要忽略nocache等字样强制存储,也就是说proxy_ignore_headers指令慎用,比如一些图片验证码和一些php、jsp、asp等动态内容在存储了后,用户多次访问会返回同样的信息,导致用户报障。还有一类资源是没有明确生命周期缓存头的(无cache-control或expires),也就是没有任何缓存要求,建议采用保守方式不要存储,主要是proxy_cache_valid指令的配置,有cookie的信息nginx默认就是不存的。对于故障信息的存储根据实际业务处理,有些故障信息是有必要存储的,还有任何资源如果源站出问题,要设置吐过期资源给用户,做到起码用户可以访问,保护一下源站。个别资源的缓存处理根据业务需要个别设置。


©本站文章(技术文章和tank手记)均为社长"矢量比特"工作.实践.学习中的心得原创或手记,请勿转载!

喜欢 (60) or 分享 (0)
欢迎扫描关注微信公众号【运维网咖社
社长"矢量比特",曾就职中软、新浪,现任职小米,致力于DevOps运维体系的探索和运维技术的研究实践.