动态PHP电商网站伪静态的 Nginx反向代理Cache缓存终极设置

背景介绍:

最近为电子商务网站设置伪静态和Nginx反向代理cache缓存,进过长时间的调试,终于达到比较满意的效果,这里把实战经验分享给大家,希望对新人有所帮助,能节约大家的一些时间。文章中有连接到真实配置的网站,本文章中所有达到的效果,都可以到此网站去真实的查看和测试。欢迎大家批评指导和交流心得!

服务器配置:

数据服务器X + 前端缓存服务器Y。 网站数据都放在数据服务器X上,数据服务器上设置好伪静态,将需要缓存的页面,都伪静态成以.html结尾的URL。前端服务器Y只做Nginx缓存proxy_cache,缓存所有.html结尾的URL。 从安全性设计,数据服务器X 只接受前端服务器Y的请求,拒绝对其他IP进行响应。

最终效果:

  1. 不同IP的都读取缓存:所有.html结尾的伪静态页面,都能缓存起来。默认缓存3小时。这类页面属于不需要实时更新数据的,实际上都是php动态程序。只要有一次访问,页面就缓存在前端服务器Y里面,3小时内,其余所有不同IP访问都不再访问数据服务器X,而全部只在前端服务器Y里 进行响应。
  2. 访问过的连接,从客户电脑读取文件:直接输入网址,或者网站各个后缀是.html的连接,点击过一次之后,再次点击,实现http状态200 cache缓存效果。就是说,某个连接点击过一次之后,再次点击,将不再对前端服务器Y发出任何请求,而是直接读取终端客户电脑的缓存数据。直接输入网址,然后回车,也是一样的效果。极大的提高前端服务器Y的效率。
  3. 浏览器刷新按钮,服务器不传输数据:对实际上是动态php程序但已经伪静态的.html的页面,点击鼠标右键的刷新按钮,或点击浏览器上面的刷新按钮,只是对前端服务器Y发出header头检查,返回304状态,然后读取终端客户电脑的缓存数据。极大的节约前端服务器Y的带宽。
  4. 强制Ctrl+F5刷新,才读取数据:这实际上就是模拟第一次访问,在默认的3小时缓存期间,http返回200状态,从前端服务器Y读取数据。数据服务器X 仍然不需要做出任何响应。
    实际应用举例:懂得按Ctrl+F5强行刷新的人,基本上都是技术员或程序员。而且基本上都是在模拟测试第一次访问的效果。真实的客户,没有人懂得这样做的。既然你懂这样做,那么就打开firefox的debug软件来看看效果吧!详情请看下面的图片。

期望达到的目的和实现方法详细介绍:

1.不同IP的访问全部命中缓存,百万访问量只查询8次数据服务器:所有.html结尾的伪静态页面,都能缓存起来。默认缓存3小时。首页被1个人访问过之后,不论这个人在哪里,上海,北京,深圳,美国都无所谓。3小时内的缓存期,全球所有国家的人再次访问网站的首页,都只是访问的前端Y服务器,而数据服务器X没有任何负担,数据库0压力。

实际应用举例:的首页被1个人访问过之后,不论这个人在哪里,上海,北京,深圳,美国都无所谓。3小时内的缓存期,全球所有国家的人再次访问网站的首页,都只是访问的前端Y服务器,而数据服务器X没有任何负担,数据库0压力。3小时后,第一个访问首页的人,将会去数据服务器X读取一次实时的数据,查询一次数据库,然后3小时内,其他所有人的访问,又全部是从前端服务器Y中读取了。也就是说,一天24小时内,首页在数据服务器X中,理论上应该只有8次访问记录(24除以3等于8),其他所有的访问,无论是几千还是几万,还是几百万次首页的访问,都是前端服务器Y的事情了。

Firefox的debug效果截图:
nginx
实现方法:这个是nginx最基本的proxy_cache的设置,网络上搜索大量的教材,这里就不累赘。节选部分吧。

默认全局缓存的代码如下,包括所有的后缀,只要是/目录下的都缓存。后面在把.php结尾的设置为不需要缓存即可。

缓存3个小时:

查看缓存是否成功:

缓存成功,X-Cache-STatus 就是HIT,读取数据没缓存就是 MISS,其他状态百度一查就知道了,这里不累赘。

重点1来了:在测试把动态php程序伪静态成.html文件的Nginx缓存的时候,发现nginx无法缓存,proxy_cache失败. 我们监控日志访问情况,发现无论怎么访问伪静态的html文件,都会直接访问数据服务器,就是说没有缓存起来。例如,我们使用 curl -I http://www.xinxilan.online/ 来查看响应头:

上面的响应头里面可以看到我预设的 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;

测试验证方法:

  1. 使用firefox的debug查看x-cache-status状态,确认是hit
  2. 监控数据服务器X的访问日志,确保多次ctrl+f5强制刷新,只有一条访问记录

2. 输入网址回车,或访问过的连接,再次点击,不经过服务器,直接读取电脑本地缓存:网站的各个后缀是.html的连接,点击过一次之后,再次点击,实现http状态200 cache缓存效果。就是说,某个连接点击过一次之后,再次点击,将不再对前端服务器Y发出任何请求,而是直接读取终端客户电脑的缓存数据。极大的提高前端服务器Y的效率。

实际应用举例:假设你已经访问了首页,然后随便点击网站里面的其他连接看看逛一逛,接着,你再用鼠标点击网站里面的某个连接进入首页,这时候,首页的数据(不包括图片css,js等其他文件)完全是从你的电脑缓存读取的,即使是前端服务器Y都没有任何响应记录。日志文件也没有任何访问记录。

Firefox的debug效果截图:

nginx

nginx

在来看下chrome浏览器的debug效果,直接就写明了 Status Code: 200 OK ( from cache )

nginx

实现方法:

在上面的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

测试验证方法:

  1. 监控前端服务器Y的访问日志
  2. 鼠标点击网站里已经访问过的.html的网页连接,访问日志里面应该没有任何记录
  3. 网站的网页能正常打开

3. 使劲点击浏览器的刷新按钮,前端服务器Y也不传输任何数据:对实际上是动态php程序但已经伪静态的.html的页面,点击鼠标右键的刷新按钮,或点击浏览器上面的刷新按钮,只是对前端服务器Y发出header头检查,返回304状态,然后读取终端客户电脑的缓存数据。极大的节约前端服务器Y的带宽。
实际应用举例:假设你已经访问了首页,然后你点击浏览器的刷新按钮,这时候你的浏览器对前端服务器Y发出请求,但是却得到304网页内容没有修改过的http返回状态,于是,浏览器还是从你的电脑缓存读取数据。这时候,我们分析前端Y服务器的日志可以发现,有一条访问日志,304状态,传输0字节!0字节!带宽完全被节约下来了,客户访问速度理论上应该是刷刷的有没有。。

Firefox的debug效果截图:

nginx

实现方法:

我们需要传递Last-Modified头部,并设置好正确的时间,来实现304的状态。首先,我查找了nginx的文档,希望能找到缓存文件真实的cache时间的参数,但是没有找到。如果你找到了这个参数,一定告诉我。

于是,另辟蹊径,在php程序的公共include文件里面,增加了header头部,来设置Last-Modified参数。默认的,php等动态程序,是不会返回Last-Modified参数。

测试验证方法:

  1. 监控前端服务器Y的访问日志
  2. 点击浏览器的刷新按钮,或鼠标右键点刷新按钮,刷新已经访问过的.html的网页
  3. 访问日志里面应该有一条304的访问记录,传输字节数为0
  4. 网站的网页能正常打开

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效果截图:

nginx

测试验证方法:

  1. 监控前端服务器Y的访问日志
  2. 同时按ctrl+f5两个按钮强制刷新页面(如果有Fn键,可能还需要按住Fn)
  3. 每一次强制刷新,访问日志里面应该有一条200的访问记录,传输字节数为文档的实际大小
  4. 网站的网页能正常打开

如何在日志里面记录每一次的访问是否有命中cache?

实现方法:

在日志格式里面加上upstream_cache_status变量,如:

测试验证方法:

日志里面应会有如下类似的记录:

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" "-"

原创作者:Macro Zeng

书写时间:2016年10月19日 夜间

版权说明:欢迎大家交流和分享经验,欢迎转载,对保留全文的同志表示感谢!

    A+
发布日期:2016年10月20日  所属分类:Nginx
标签:
teakki

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:3   其中:访客  3   博主  0

  1. 1111 5

    不错! 写的挺好!

    • 5555 5

      @1111 楼主是否可以分享一下 conf.proxy_online_cache 配置文件

      • wangzhigang1101 0

        @5555 同问