Nginx模块fastcgicache的几个注意点.docx
- 文档编号:11340040
- 上传时间:2023-05-31
- 格式:DOCX
- 页数:12
- 大小:145.93KB
Nginx模块fastcgicache的几个注意点.docx
《Nginx模块fastcgicache的几个注意点.docx》由会员分享,可在线阅读,更多相关《Nginx模块fastcgicache的几个注意点.docx(12页珍藏版)》请在冰点文库上搜索。
Nginx模块fastcgicache的几个注意点
Nginx模块fastcgi_cache的几个注意点
在web项目中,大家都已经非常熟悉其架构流程了。
都说Cache是万金油,哪里不舒服抹哪里。
这些流程中,几乎每个环节都会进行cache。
从浏览器到webserver,到cgi程序,到DB数据库,会进行浏览器cache,数据cache,SQL查询的cache等等。
对于fastcgi这里的cache,很少被使用。
去年年底,我对nginx的fastcgi_cache进行摸索使用。
在我的测试过程中,发现一些WIKI以及网络上没被提到的注意点,这里分享一下。
从浏览器到数据库的流程图
这里是我的NGinx配置信息
#增加调试信息
add_headerX-Cache-CFC"$upstream_cache_status-$upstream_response_time";
fastcgi_temp_path/dev/shm/nginx_tmp;
#cache设置
fastcgi_cache_path/dev/shm/nginx_cachelevels=1:
2keys_zone=cfcache:
10minactive=50m;
fastcgi_cache_key"$request_method:
//$host$request_uri";
fastcgi_cache_methodsGETHEAD;
fastcgi_cachecfcache;
fastcgi_cache_validany1d;
fastcgi_cache_min_uses1;
fastcgi_cache_use_staleerrortimeoutinvalid_headerhttp_500;
fastcgi_ignore_client_aborton;
配置这些参数时,注意每个参数的作用域,像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,requestwaspassedtobackendCache已过期
UPDATING–expired,staleresponsewasusedduetoproxy/fastcgi_cache_use_staleupdatingCache已过期,(被其他nginx子进程)更新中
STALE–expired,staleresponsewasusedduetoproxy/fastcgi_cache_use_staleCache已过期,响应数据不合法,被污染
HIT命中cache
FASTCGI_CACHE$upstream_cache_status结果为miss,一次也没命中
程序代码是Discuz!
论坛,随便开启测试了几下,发现/dev/shm/nginx_cache/下没有任何目录建立,也没有文件创建。
调试的httpheader响应头里的X-Cache-CFC结果一直是MISS。
从服务器进程上来看,Nginxcachemanagerprocess跟Nginxcacheloaderprocess进程也正常运行:
root31001014:
52?
00:
00:
00nginx:
masterprocess/usr/sbin/nginx
www-data31013100014:
52?
00:
00:
00nginx:
workerprocess
www-data31023100014:
52?
00:
00:
00nginx:
cachemanagerprocess
www-data31033100014:
52?
00:
00:
00nginx:
cacheloaderprocess
不知道为何会这样,为何没有cache成功,我以为我配置参数有问题,只好阅读WIKI。
发现fastcgi_ignore_headers参数下解释有这么一段
fastcgi_ignore_headers
Syntax:
fastcgi_ignore_headersfield…
Default:
Context:
http
server
location
Reference:
fastcgi_ignore_headers
ThisdirectiveforbidsprocessingofthenamedheadersfromtheFastCGI-serverreply.Itispossibletospecifyheaderslike“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进程通讯的数据
####为了确保准确抓到处理该http请求的进程,我把nginx、fpm都只开启了一个进程处理。
//strace-ff-tt-s1000-oxxx.log-pPHPFPM-PID
14:
52:
07.837334write(3,"\1\6\0\1\0\343\5\0X-Powered-By:
PHP/5.3.10-1ubuntu3.5\r\nExpires:
Thu,19Nov198108:
52:
00GMT\r\nCache-Control:
no-store,no-cache,must-revalidate,post-check=0,pre-check=0\r\nPragma:
no-cache\r\nContent-type:
text/html\r\n\r\nHellocfc4n1362034327\0\0\0\0\0\1\3\0\1\0\10\0\0\0\0\0\0\0\0\0\0",256)=256
//strace-ff-tt-s1000-oxxx.log-pNginx-PID
15:
05:
13.265663recvfrom(12,"\1\6\0\1\0\343\5\0X-Powered-By:
PHP/5.3.10-1ubuntu3.5\r\nExpires:
Thu,19Nov198108:
52:
00GMT\r\nCache-Control:
no-store,no-cache,must-revalidate,post-check=0,pre-check=0\r\nPragma:
no-cache\r\nContent-type:
text/html\r\n\r\nHellocfc4n1362035113\0\0\0\0\0\1\3\0\1\0\10\0\0\0\0\0\0\0\0\0\0",4023,0,NULL,NULL)=256
从抓取的数据包里可以看到,fpm确实返回了包含“Expires”、“Cache-Control”头的http响应头信息。
那么疑问来了:
nginx的fastcgi_cache没缓存这条http响应,是因为响应头里包含“Expires”、“Cache-Control”的原因吗?
程序里并没有输出“Expires”、“Cache-Control”httpheader的代码,这是谁输出的呢?
既然是fpm响应的时候,就已经有了,那么是php的core模块,还是其他拓展模块输出的?
“Expires:
”时间为何是“Thu,19Nov198108:
52:
00GMT”?
疑问比较多,一个一个查起,先从Nginx的fastcgi_cache没缓存这条http响应查起。
我根据测试环境nginx版本1.1.9(ubuntu12.04默认的),到nginx官方下了对应版本的源码,搜索了fastcgi参数使用的地方,在http\ngx_http_upstream.c找到了。
虽然不能很流程的读懂nginx的代码,但粗略的了解,根据了解的情况加以猜测,再动手测试实验,也得出了结论,确定了nginx的fastcgi_cache的规则。
//ngx_http_upstream.c
//line3136当fastcgi响应包含set-cookie时,不缓存
staticngx_int_t
ngx_http_upstream_process_set_cookie(ngx_http_request_t*r,ngx_table_elt_t*h,
ngx_uint_toffset)
{
#if(NGX_HTTP_CACHE)
ngx_http_upstream_t*u;
u=r->upstream;
if(!
(u->conf->ignore_headers&NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)){
u->cacheable=0;
}
#endif
returnNGX_OK;
}
//line3242当响应头包含Expires时,如果过期时间大于当前服务器时间,则nginx_cache会缓存该响应,否则,则不缓存
staticngx_int_t
ngx_http_upstream_process_expires(ngx_http_request_t*r,ngx_table_elt_t*h,
ngx_uint_toffset)
{
ngx_http_upstream_t*u;
u=r->upstream;
u->headers_in.expires=h;
#if(NGX_HTTP_CACHE)
{
time_texpires;
if(u->conf->ignore_headers&NGX_HTTP_UPSTREAM_IGN_EXPIRES){
returnNGX_OK;
}
if(r->cache==NULL){
returnNGX_OK;
}
if(r->cache->valid_sec!
=0){
returnNGX_OK;
}
expires=ngx_http_parse_time(h->value.data,h->value.len);
if(expires==NGX_ERROR||expires
returnNGX_OK;
}
r->cache->valid_sec=expires;
}
#endif
returnNGX_OK;
}
//line3199当响应头包含Cache-Control时,#####如果####这里有如果啊。
。
。
//【注意】如果Cache-Control参数值为no-cache、no-store、private中任意一个时,则不缓存...不缓存...
//【注意】如果Cache-Control参数值为max-age时,会被缓存,且nginx设置的cache的过期时间,就是系统当前时间+mag-age的值
if(ngx_strlcasestrn(p,last,(u_char*)"no-cache",8-1)!
=NULL
||ngx_strlcasestrn(p,last,(u_char*)"no-store",8-1)!
=NULL
||ngx_strlcasestrn(p,last,(u_char*)"private",7-1)!
=NULL)
{
u->cacheable=0;
returnNGX_OK;
}
p=ngx_strlcasestrn(p,last,(u_char*)"max-age=",8-1);
if(p==NULL){
returnNGX_OK;
}
...
r->cache->valid_sec=ngx_time()+n;
也就是说,fastcgi响应http请求的结果中,响应头包括Expires、Cache-Control、Set-Cookie三个,都会可能不被cache,但不只有这些,别忘了nginx配置中fastcgi_ignore_headers参数设定的部分。
以及ngxin的X-ACCELX-Accel-Redirect、X-Accel-Expires、X-Accel-Charset、X-Accel-Buffering等nginx自定义的响应头。
由于这几个不常用,我也没深入研究。
通过对nginx的ngx_http_upstream模块代码模糊理解,加猜测,以及写了脚本测试验证,可以得到结论是正确的。
即Nginxfastcgi_cache在缓存后端fastcgi响应时,当响应里包含“set-cookie”时,不缓存;当响应头包含Expires时,如果过期时间大于当前服务器时间,则nginx_cache会缓存该响应,否则,则不缓存;当响应头包含Cache-Control时,如果Cache-Control参数值为no-cache、no-store、private中任意一个时,则不缓存,如果Cache-Control参数值为max-age时,会被缓存,且nginx设置的cache的过期时间,就是系统当前时间+mag-age的值。
nginxfastcgi_cache响应expired
nginxfastcgi_cachehit命中
FASTCGI_CACHE$upstream_cache_status结果为miss,一次也没命中。
//逐个测试,测试时,注释其他的
header("Expires:
".gmdate("D,dMYH:
i:
s",time()+10000).'GMT');
header("Expires:
".gmdate("D,dMYH:
i:
s",time()-99999).'GMT');
header("X-Accel-Expires:
30");
header("Cache-Control:
no-cache");
header("Cache-Control:
no-store");
header("Cache-Control:
private");
header("Cache-Control:
max-age=10");
setcookie('cfc4n',"testaaaa");
echo'Hellocfc4n',time();
到了这里,疑问1解决了。
那么疑问2、3呢?
程序里并没有输出“Expires”、“Cache-Control”httpheader的代码,这是谁输出的呢?
既然是fpm响应的时候,就已经有了,那么是php的core模块,还是其他拓展模块输出的?
我精简了代码,只输出一个“helloworld”,发现也确实被缓存了。
显然,php脚本程序中并没输出httpheader的“Expires”、“Cache-Control”,多次测试,最终定位到session_start函数,翻阅源码找到了这些代码:
//ext/session/session.cline:
1190左右
//...
CACHE_LIMITER_FUNC(private)/*{{{*/
{
ADD_HEADER("Expires:
Thu,19Nov198108:
52:
00GMT");
CACHE_LIMITER(private_no_expire)(TSRMLS_C);
}
/*}}}*/
//再到这里3或者上面几个##默认是nocache
CACHE_LIMITER_FUNC(nocache)/*{{{*/
{
ADD_HEADER("Expires:
Thu,19Nov198108:
52:
00GMT");
/*ForHTTP/1.1conformingclientsandtherest(MSIE5)*/
ADD_HEADER("Cache-Control:
no-store,no-cache,must-revalidate,post-check=0,pre-check=0");
/*ForHTTP/1.0conformingclients*/
ADD_HEADER("Pragma:
no-cache");
}
/*}}}*/
//这里2
staticphp_session_cache_limiter_tphp_session_cache_limiters[]={
CACHE_LIMITER_ENTRY(public)
CACHE_LIMITER_ENTRY(private)
CACHE_LIMITER_ENTRY(private_no_expire)
CACHE_LIMITER_ENTRY(nocache)
{0}
};
staticintphp_session_cache_limiter(TSRMLS_D)/*{{{*/
{
php_session_cache_limiter_t*lim;
if(PS(cache_limiter)[0]=='\0')return0;
if(SG(headers_sent)){
constchar*output_start_filename=php_output_get_start_filename(TSRMLS_C);
intoutput_start_lineno=php_output_get_start_lineno(TSRMLS_C);
if(output_start_filename){
php_error_docref(NULLTSRMLS_CC,E_WARNING,"Cannotsendsessioncachelimiter-headersalreadysent(outputstartedat%s:
%d)",output_start_filename,output_start_lineno);
}else{
php_error_docref(NULLTSRMLS_CC,E_WARNING,"Cannotsendsessioncachelimiter-headersalreadysent");
}
return-2;
}
for(lim=php_session_cache_limiters;lim->name;lim++){
if(!
strcasecmp(lim->name,PS(cache_limiter))){
lim->func(TSRMLS_C);//这里1
return0;
}
}
return-1;
}
//...
到了这里,知道原因了,是程序调用session_start时,php的session拓展自己输出的。
session.cache_limit参数来决定输出包含哪种Expires的header,默认是nocache,修改php.ini的session.cache_limit参数为“none”即可让session模块不再输出这些http响应头。
或在调用session_start之前,使用session_cache_limiter函数来指定下该参数值。
那为什么要在使用session时,发Expires、Cache-Control的httpresponseheader呢?
我猜测了下,需要session时,基本上是用户跟服务器有交互,那么,既然有交互,就意味着用户的每次交互结果也可能不一样,就不能cache这个请求的结果,给返回给这个用户。
同时,每个用户的交互结果都是不一样的,nginx也就不能把包含特殊Cache-Control的个人响应cache给其他人提供了。
还有一个无聊的问题“Expires:
时间为何是Thu,19Nov198108:
52:
00GMT”?
我翻阅了session.c这段代码的添加时间,版本,作者信息,在php官方版本库中找到了这次提交的信息:
Revision17092–(view)(download)(astext)(annotate)–[selectfordiffs]
ModifiedSunDec1214:
16:
551999UTC(13years,2monthsago)bysas
Filelength:
28327byte(s)
Difftoprevious16964
Addcache_limiterandcache_expireoptions.Renameextern_referer_check
toreferer_check.
对比session.c两个版本的变更,果然是这块代码。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Nginx 模块 fastcgicache 几个 注意