背景介绍:
最近为电子商务网站 www.XinXiLan.online 新西兰购物网 设置伪静态和Nginx反向代理cache缓存,进过长时间的调试,终于达到比较满意的效果,这里把实战经验分享给大家,希望对新人有所帮助,能节约大家的一些时间。文章中有连接到真实配置的网站 www.XinXiLan.online 新西兰购物网 转载请保留此连接,本文章中所有达到的效果,都可以到 www.XinXiLan.online 新西兰购物网 去真实的查看和测试。欢迎大家批评指导和交流心得!
服务器配置:
数据服务器X + 前端缓存服务器Y。 网站数据都放在数据服务器X上,数据服务器上设置好伪静态,将需要缓存的页面,都伪静态成以.html结尾的URL。前端服务器Y只做Nginx缓存proxy_cache,缓存所有.html结尾的URL。 从安全性设计,数据服务器X 只接受前端服务器Y的请求,拒绝对其他IP进行响应。
最终效果:
不同IP的都读取缓存:所有.html结尾的伪静态页面,都能缓存起来。默认缓存3小时。这类页面属于不需要实时更新数据的,实际上都是php动态程序。只要有一次访问,页面就缓存在前端服务器Y里面,3小时内,其余所有不同IP访问都不再访问数据服务器X,而全部只在前端服务器Y里 进行响应。
访问过的连接,从客户电脑读取文件:直接输入网址,或者网站各个后缀是.html的连接,点击过一次之后,再次点击,实现http状态200 cache缓存效果。就是说,某个连接点击过一次之后,再次点击,将不再对前端服务器Y发出任何请求,而是直接读取终端客户电脑的缓存数据。直接输入网址,然后回车,也是一样的效果。极大的提高前端服务器Y的效率。
浏览器刷新按钮,服务器不传输数据:对实际上是动态php程序但已经伪静态的.html的页面,点击鼠标右键的刷新按钮,或点击浏览器上面的刷新按钮,只是对前端服务器Y发出header头检查,返回304状态,然后读取终端客户电脑的缓存数据。极大的节约前端服务器Y的带宽。
强制Ctrl+F5刷新,才读取数据:这实际上就是模拟第一次访问,在默认的3小时缓存期间,http返回200状态,从前端服务器Y读取数据。数据服务器X 仍然不需要做出任何响应。
实际应用举例:懂得按Ctrl+F5强行刷新的人,基本上都是技术员或程序员。而且基本上都是在模拟测试第一次访问的效果。真实的客户,没有人懂得这样做的。既然你懂这样做,那么就打开firefox的debug软件来看看效果吧!详情请看下面的图片。
期望达到的目的和实现方法详细介绍:
1.不同IP的访问全部命中缓存,百万访问量只查询8次数据服务器:所有.html结尾的伪静态页面,都能缓存起来。默认缓存3小时。首页被1个人访问过之后,不论这个人在哪里,上海,北京,深圳,美国都无所谓。3小时内的缓存期,全球所有国家的人再次访问网站的首页,都只是访问的前端Y服务器,而数据服务器X没有任何负担,数据库0压力。
实际应用举例:www.XinXiLan.online 新西兰购物网 的首页被1个人访问过之后,不论这个人在哪里,上海,北京,深圳,美国都无所谓。3小时内的缓存期,全球所有国家的人再次访问网站的首页,都只是访问的前端Y服务器,而数据服务器X没有任何负担,数据库0压力。3小时后,第一个访问首页的人,将会去数据服务器X读取一次实时的数据,查询一次数据库,然后3小时内,其他所有人的访问,又全部是从前端服务器Y中读取了。也就是说,一天24小时内,www.XinXiLan.online 新西兰购物网 的首页在数据服务器X中,理论上应该只有8次访问记录(24除以3等于8),其他所有的访问,无论是几千还是几万,还是几百万次首页的访问,都是前端服务器Y的事情了。
Firefox的debug效果截图:
实现方法:这个是nginx最基本的proxy_cache的设置,网络上搜索大量的教材,这里就不累赘。节选部分吧。
默认全局缓存的代码如下,包括所有的后缀,只要是/目录下的都缓存。后面在把.php结尾的设置为不需要缓存即可。
location / { proxy_pass http://www.xinxilan.online/ ; include vhosts/conf.proxy_online_cache; }
缓存3个小时:
proxy_cache_valid 200 302 3h; proxy_cache_valid 301 3h; proxy_cache_valid any 30m;
查看缓存是否成功:
add_header X-Cache-Status $upstream_cache_status;
缓存成功,X-Cache-STatus 就是HIT,读取数据没缓存就是 MISS,其他状态百度一查就知道了,这里不累赘。
重点1来了:在测试把动态php程序伪静态成.html文件的Nginx缓存的时候,发现nginx无法缓存,proxy_cache失败. 我们监控日志访问情况,发现无论怎么访问伪静态的html文件,都会直接访问数据服务器,就是说没有缓存起来。例如,我们使用 curl -I http://www.XinXiLan.online/ 来查看响应头:
HTTP/1.1 200 OK Server: nginx/1.11.4 Date: Mon, 03 Oct 2016 02:19:47 GMT Content-Type: text/html; charset=utf-8 Connection: keep-alive X-Powered-By: PHP/5.3.3 Cache-control: private Set-Cookie: ECS_ID=abd942b0af8a00074455befa7e9672a765cdcd85; path=/ Set-Cookie: ECS[visit_times]=1; expires=Mon, 02-Oct-2017 18:19:47 GMT; path=/ Set-Cookie: ECS[history]=127; expires=Tue, 01-Nov-2016 18:19:47 GMT Vary: Accept-Encoding X-Cache: www.XinXiLan.online-Nginx-Cached X-Cache-Status: MISS
上面的响应头里面可以看到我预设的 X-Cache: www.XinXiLan.online-Nginx-Cached,说明实际上已经调用了conf.proxy_online_cache 配置文件,但是X-Cache-Status: MISS,说明没有缓存成功。怎么回事呢?进过研究,原来是php程序传递了header头 Cache-control 和 Set-Cookie,导致nginx默认就不缓存这类文件。
解决办法:
在nginx的conf.proxy_online_cache配置文件里面,忽略掉header头 Cache-control 和 Set-Cookie
proxy_ignore_headers Cache-Control Set-Cookie;
重点2来了:如何确保一个人访问,全世界所有其他人都读取缓存内容呢?如何确保一天24小时,只有8次访问数据服务器X呢?
接下来的测试中, 进一步发现,使用不同的浏览器访问同一个文件,即使是在cache缓存的有效期里面,不同浏览器并不会直接读取cache,不同的browser会单独发起请求,这坑爹吧,基本上就等于是每个客户的浏览器都要缓存一次网站的内容,cache就失去意义了。
为什么会这样?应该是不同的浏览器、包括不同的版本,传送了不同的参数给nginx,导致nginx认为是不同的请求。
怎么办?理论上要忽略不同的browser即可。
看下解决办法,在上面的conf.proxy_online_cache配置文件里面继续忽略 Vary 的header参数:
proxy_ignore_headers Cache-Control Set-Cookie Vary;
测试验证方法:
使用firefox的debug查看x-cache-status状态,确认是hit
监控数据服务器X的访问日志,确保多次ctrl+f5强制刷新,只有一条访问记录
2. 输入网址回车,或访问过的连接,再次点击,不经过服务器,直接读取电脑本地缓存:网站的各个后缀是.html的连接,点击过一次之后,再次点击,实现http状态200 cache缓存效果。就是说,某个连接点击过一次之后,再次点击,将不再对前端服务器Y发出任何请求,而是直接读取终端客户电脑的缓存数据。极大的提高前端服务器Y的效率。
实际应用举例:假设你已经访问了 www.XinXiLan.online 新西兰购物网 的首页,然后随便点击网站里面的其他连接看看逛一逛,接着,你再用鼠标点击网站里面的某个连接进入首页,这时候,首页的数据(不包括图片css,js等其他文件)完全是从你的电脑缓存读取的,即使是前端服务器Y都没有任何响应记录。日志文件也没有任何访问记录。
Firefox的debug效果截图:
在来看下chrome浏览器的debug效果,直接就写明了 Status Code: 200 OK ( from cache )
实现方法:
在上面的conf.proxy_online_cache配置文件里面:
Cache-control: private => 改为 Cache-Control: max-age=10800
Set-Cookie: => 需要去掉。但是在nginx里面,默认是无法去掉php程序里面已经传递的header头的。也就是说在php程序里面,要缓存的页面,不要使用setcookie函数,如果一定要设置cookie,用javascript去做。
去掉header里面的etag,增加 X-Accel-Expires: 10800
add_header X-Accel-Expires 10800; add_header Cache-Control 'max-age=10800';
测试验证方法:
监控前端服务器Y的访问日志
鼠标点击网站里已经访问过的.html的网页连接,访问日志里面应该没有任何记录
网站的网页能正常打开
3. 使劲点击浏览器的刷新按钮,前端服务器Y也不传输任何数据:对实际上是动态php程序但已经伪静态的.html的页面,点击鼠标右键的刷新按钮,或点击浏览器上面的刷新按钮,只是对前端服务器Y发出header头检查,返回304状态,然后读取终端客户电脑的缓存数据。极大的节约前端服务器Y的带宽。
实际应用举例:假设你已经访问了 www.XinXiLan.online 新西兰购物网 的首页,然后你点击浏览器的刷新按钮,这时候你的浏览器对前端服务器Y发出请求,但是却得到304网页内容没有修改过的http返回状态,于是,浏览器还是从你的电脑缓存读取数据。这时候,我们分析前端Y服务器的日志可以发现,有一条访问日志,304状态,传输0字节!0字节!带宽完全被节约下来了,客户访问速度理论上应该是刷刷的有没有。。
Firefox的debug效果截图:
实现方法:
我们需要传递Last-Modified头部,并设置好正确的时间,来实现304的状态。首先,我查找了nginx的文档,希望能找到缓存文件真实的cache时间的参数,但是没有找到。如果你找到了这个参数,一定告诉我。
于是,另辟蹊径,在php程序的公共include文件里面,增加了header头部,来设置Last-Modified参数。默认的,php等动态程序,是不会返回Last-Modified参数。
header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T', time()));
测试验证方法:
监控前端服务器Y的访问日志
点击浏览器的刷新按钮,或鼠标右键点刷新按钮,刷新已经访问过的.html的网页
访问日志里面应该有一条304的访问记录,传输字节数为0
网站的网页能正常打开
www.xinxilan.online - 14.221.50.31 - HIT [19/Oct/2016:20:10:46 +0800] "GET / HTTP/1.1" 304 0 "http://www.xinxilan.online/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"
www.xinxilan.online - 14.221.50.31 - HIT [19/Oct/2016:20:10:48 +0800] "GET / HTTP/1.1" 304 0 "http://www.xinxilan.online/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"
4. 强制Ctrl+F5刷新,模拟网友的第一次访问。在默认的3小时缓存期间,http返回200状态,从前端服务器Y读取数据。数据服务器X 仍然不需要做出任何响应。
实际应用举例:懂得按Ctrl+F5强行刷新的人,基本上都是技术员或程序员。而且基本上都是在模拟测试第一次访问的效果。真实的客户,没有人懂得这样做的。既然你懂这样做,那么就打开firefox的debug软件来看看效果吧!详情请看下面的图片。
Firefox的debug效果截图:
测试验证方法:
监控前端服务器Y的访问日志
同时按ctrl+f5两个按钮强制刷新页面(如果有Fn键,可能还需要按住Fn)
每一次强制刷新,访问日志里面应该有一条200的访问记录,传输字节数为文档的实际大小
网站的网页能正常打开
如何在日志里面记录每一次的访问是否有命中cache?
实现方法:
在日志格式里面加上upstream_cache_status变量,如:
log_format main '$host - $remote_addr - $upstream_cache_status [$time_local] "$request" '
测试验证方法:
日志里面应会有如下类似的记录:
www.xinxilan.online - 14.221.50.31 - HIT [19/Oct/2016:20:11:20 +0800] "GET /category-35-b0.html HTTP/1.1" 304 0 "http://www.xinxilan.online/category-34-b0.html" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"
www.xinxilan.online - 66.249.69.214 - MISS [19/Oct/2016:20:11:40 +0800] "GET /category-1-b2-min0-max0-attr31.2.html HTTP/1.1" 200 5054 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "-"
www.xinxilan.online - 14.221.50.31 - HIT [19/Oct/2016:20:12:16 +0800] "GET /category-7-b0.html HTTP/1.1" 200 9360 "http://www.xinxilan.online/category-13-b0.html" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"
www.xinxilan.online - 14.221.50.31 - BYPASS [19/Oct/2016:20:12:36 +0800] "GET /category-7-b0.html?nocache=1 HTTP/1.1" 304 0 "http://www.xinxilan.online/category-13-b0.html" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"