Nginx模块fastcgi_cache的几个注意点
在web项目中,大家都已经非常熟悉其架构流程了。都说Cache是万金油,哪里不舒服抹哪里。这些流程中,几乎每个环节都会进行cache。从浏览器到webserver,到cgi程序,到DB数据库,会进行浏览器cache,数据cache,SQL查询的cache等等。对于fastcgi这里的cache,很少被使用。去年年底,我对nginx的fastcgi_cache进行摸索使用。在我的测试过程中,发现一些WIKI以及网络上没被提到的注意点,这里分享一下。
从浏览器到数据库的流程图
这里是我的NGinx配置信息
配置这些参数时,注意每个参数的作用域,像fastcgi_cache_path参数,只能在http配置项里配置,而fastcgi_cache_min_uses这个参数,可以在http、server、location三个配置项里配置。这样更灵活的会每个域名、每个匹配的location进行选择性cache了。具体的参数作用域,参考FASTCGI模块的官方WIKI。我为了调试方便,添加了一个『X-Cache-CFC』的http响应头,$upstream_cache_status 变量表示此请求响应来自cache的状态,分别为:
- MISS 未命中
- EXPIRED – expired, request was passed to backend Cache已过期
- UPDATING – expired, stale response was used due to proxy/fastcgi_cache_use_stale updating Cache已过期,(被其他nginx子进程)更新中
- STALE – expired, stale response was used due to proxy/fastcgi_cache_use_stale Cache已过期,响应数据不合法,被污染
- HIT 命中cache
FASTCGI_CACHE $upstream_cache_status 结果为miss,一次也没命中
程序代码是Discuz!论坛, 随便开启测试了几下,发现/dev/shm/nginx_cache/下没有任何目录建立,也没有文件创建。调试的http header响应头里的X-Cache-CFC 结果一直是MISS。从服务器进程上来看,Nginx cache manager process 跟Nginx cache loader process 进程也正常运行:
fastcgi_ignore_headers
Syntax: fastcgi_ignore_headers field …
Default:
Context: http
server
location
Reference: fastcgi_ignore_headersThis directive forbids processing of the named headers from the FastCGI-server reply. It is possible to specify headers like “X-Accel-Redirect”, “X-Accel-Expires”, “Expires” or “Cache-Control”.
也就是说这个参数的值,将会被忽略掉,同样被忽略掉的响应头比如”X-Accel-Redirect”, “X-Accel-Expires”, “Expires” or “Cache-Control”,而nginx配置中并没有fastcgi_ignore_headers参数的设定,那么问题会不会出现在FASTCGI响应结果里包含了类似”X-Accel-Redirect”, “X-Accel-Expires”, “Expires” or “Cache-Control”这几个响应头呢?用strace抓包,看了下nginx与fpm进程通讯的数据
- nginx的fastcgi_cache没缓存这条http响应,是因为响应头里包含“Expires”、“Cache-Control”的原因吗?
- 程序里并没有输出“Expires”、“Cache-Control” http header的代码,这是谁输出的呢?
- 既然是fpm响应的时候,就已经有了,那么是php的core模块,还是其他拓展模块输出的?
- “Expires:”时间为何是“Thu, 19 Nov 1981 08:52:00 GMT”?
疑问比较多,一个一个查起,先从Nginx的fastcgi_cache没缓存这条http响应查起。我根据测试环境nginx版本1.1.9(ubuntu 12.04默认的),到nginx官方下了对应版本的源码,搜索了fastcgi参数使用的地方,在http\ngx_http_upstream.c找到了。虽然不能很流程的读懂nginx的代码,但粗略的了解,根据了解的情况加以猜测,再动手测试实验,也得出了结论,确定了nginx的fastcgi_cache的规则。
nginx fastcgi_cache 响应expired
nginx fastcgi_cache hit命中
FASTCGI_CACHE $upstream_cache_status 结果为miss,一次也没命中。
还有一个无聊的问题“Expires:时间为何是Thu, 19 Nov 1981 08:52:00 GMT”?我翻阅了session.c这段代码的添加时间,版本,作者信息,在php官方版本库中找到了这次提交的信息:
Revision 17092 – (view) (download) (as text) (annotate) – [select for diffs]
Modified Sun Dec 12 14:16:55 1999 UTC (13 years, 2 months ago) by sas
File length: 28327 byte(s)
Diff to previous 16964
Add cache_limiter and cache_expire options. Rename extern_referer_check
to referer_check.
对比session.c两个版本的变更,果然是这块代码。作者是sas,也就是Sascha Schumann, http://php.net/credits.php里可以看到他的大名。关于这个expires过期时间的问题,有人在stackoverflow也提问过,Why is “Expires” 1981?,别人说那天是他生日。这是真的么?如果那天是他生日的话,而他增加session.cache_limiter时是1999年,他才17岁,17岁呀。我17岁时在干嘛?还不知道电脑长啥样,正在玩『超级玛丽』呢。
好奇的不是我一个人,还有个帖子是epoch date — Expires: Thu, 19 Nov 1981 08:52:00也问了。另外两个地址虽然没问,也有人提到那天是他生日了。http://boinc.berkeley.edu/dev/forum_thread.php?id=2514、https://github.com/codeguy/Slim/issues/157,这些帖子都提到说原帖是http://www.phpbuilder.com/lists/php3-list/199911/3159.php ,我无法访问,被跳转到首页了。用http://web.archive.org找到了历史快照,发现上下文关系不大,也不能证明是他生日。 我更是好奇的发了两封邮件到他的不同邮箱里问他,不过,目前他还没回复。或许他没收到、没看到,或许懒得回了。N年后,“Expires:时间为何是Thu, 19 Nov 1981 08:52:00 GMT”这个日期,会不会又成了一段奇闻佳话了呢?