网站建设

解决Nginx Helper插件一键清理缓存功能导致网站打不开问题

Jager · 8月29日 · 2015年 · · 4543次已读

5 月份,张戈博客分享了一篇《Nginx 开启 fastcgi_cache 缓存加速,支持 html 伪静态页面》的文章。文中也提到了 WordPress 有一款名为 Nginx Helper 的插件是这个功能的绝佳搭配。

解决Nginx Helper插件一键清理缓存功能导致网站打不开问题

一、问题描述

不过,最近通过朋友反馈及我自己亲测发现了一个严重的问题:

Nginx Helper 设置界面有一个一键清理缓存的按钮【Purge Entire Cache】,只要在后台点击这个按钮,前台就跪了。当然,如果对登录用户不显示缓存,那么登录用户访问是正常的。

解决Nginx Helper插件一键清理缓存功能导致网站打不开问题

二、分析原因

分析了一下原因:【Purge Entire Cache】这个按钮按下后会删除 Nginx 所有的缓存,但是却不会重载(启)Nginx。那么问题来了,当在前台请求需要展示缓存的页面时,Nginx 将继续调用之前的缓存文件,然而所有缓存文件却被这个插件删除了,所以这个页面就 502 了!

清理前可以看到如图缓存文件夹:

解决Nginx Helper插件一键清理缓存功能导致网站打不开问题

但是清理后,就没了,而且也不会在生成。因为这样强行全部删除并没有“通知”Nginx ...这时候,网站就打不开了。当然,如果是设置了登录用户或已评论用户不展示缓存,那么网站会实时展示正常打开。但是要展示缓存页面就会 502 了,因为 Nginx 自己都找不到路径了。。。

三、部署解决

不难理解,要解决这个问题,比如给一键清理功能绑定一个重载 Nginx 的机制。但是一般情况下 php 并没有权限去重载或重启 Nginx 。所以,要继续使用这个一键清理功能,就只能授予 php 重启 Nginx 的权限,还需要将重启 Nginx 的命令集成到插件才行。

①、授权 php 执行系统命令

php 重启 nginx 功能,张戈博客之前已经分享过相应的办法了,请先参考部署该功能:

php 平滑重启 nginx,彻底清除 WordPress 的静态缓存

②、将重载命令加入到一键清理函数

部署 OK 之后,编辑 Nginx helper 插件下的 purger.php 文件,找到如下函数:

function true_purge_all(){
	$this->unlinkRecursive(RT_WP_NGINX_HELPER_CACHE_PATH, false);
	$this->log( "* * * * *" );
	$this->log( "* Purged Everything!" );
	$this->log( "* * * * *" );
	}

如下在函数中添加重载 nginx 的代码即可:

function true_purge_all(){
	$this->unlinkRecursive(RT_WP_NGINX_HELPER_CACHE_PATH, false);
	exec(EscapeShellCmd("/opt/reload_nginx.sh"));//一键清理后重载 nginx
	$this->log( "* * * * *" );
	$this->log( "* Purged Everything!" );
	$this->log( "* * * * *" );
	}

好了,现在点击一键清理功能,缓存会全部删除,而且 nginx 也会重载,前台网站也就不会跪了。

四、其他完善

当然,经常有人反馈偶尔更新文章,前台并不会刷新。其实,这本文陈述的情况也有关系。在使用【删除模式】时,单篇文章的缓存被清理后,也不会重载 Nginx。此时,如果此文的缓存是存放在内存的话,前台肯定就不会刷新了!

所以,我们有必要给单个清理功能也绑定一个重载 Nginx 的机制。此处为了节省数千个字,张戈决定提供全部修改好的 Nginx Helper 插件,需要的自行下载重新安装这个插件即可:

你可能会疑问为毛删除单个页面后,这个页面却还能打开?和删除全部不是一样的机制吗?

分析了下,如果类比删除全部缓存带来的问题,删除单个页面应该也会出现该页面打不开的情况才对。不过,细想了一下,解释很简单。因为删除全部缓存会破坏缓存的文件目录结构,而删除单个页面只是删除一个缓存文件,缓存的目录结构并未被破坏。

通俗来说:缓存的目录结构如同 Nginx 的一个行车路线,只有不破坏这个路径,才能正常行驶。当然了,你破坏了这个行车路线,重载一下 Nginx 它又能重新规划了。

五、更多花絮

当我发现这个问题,并解决后,还给这插件的作者发了 BUG 反馈邮件。蹩脚的中式英语并不影响交流,哈哈!

解决Nginx Helper插件一键清理缓存功能导致网站打不开问题

感兴趣的可以凑合看看:

Hello Zhang Ge,

Thanks for contacting us. This is Dinesh from rtCamp.

Sorry to hear about the problem you are facing.

Please verify if the Nginx Helper plugin is properly configured from its settings page.

As you are using Nginx FastCGI caching and the site is not loading after purging entire cache so I will suggest to try Redis cache. You can configure Redis cache option in Nginx Helper plugin once its enabled on server.

Redis cache support "Custom Purge URL" option so you can add links which you want to purge instead of purging entire cache. Also, reloading of Nginx is not needed for purging cache.

Please feel free to post your query if you are facing any problem on our community support forum (http://community.rtcamp.com/c/wordpress-nginx).

Regards, Dinesh

Hello , rtcamp:

I found a bug with your plugin that named nginx-helper.

When we click zhe Button [Purge Entire Cache], our websites  will dead immediately.

Because  [Purge Entire Cache] will clean up all of the fastcgi cache,but without reload the nginx .

So nginx can't find the cache when we request.

To fixed the bug, you could added a action of reload nginx when [Purge Entire Cache] be clicked.

FYI :

exec(EscapeShellCmd("/opt/reload_nginx.sh"));

But,it must supported by Operating environment.

My post url: https://zhang.ge/5042.html

------------------

张戈博客是关注互联网以及分享 IT 运维工作经验的个人博客,由系统运维、脚本编程以及资源分享等分类组成,涵盖了操作系统教程、运维经验、脚本语言以及网络资源等。

永久地址:https://zhang.ge
Dinesh Jain | Project Manager | rtCamp Solutions Pvt. Ltd.
Web: http://rtCamp.com | Skype: dinesh.jain.rtcamp | Twitter: @dineshjain2911

他要我去他们的论坛发帖,一起交流问题。好吧,我就去看了下,并简单的陈述了一下问题和建议,结果并没有什么卵用,因为没人回复【帖子传送门】。。。

最后,写这篇文章时,我还是单独给这哥们又发了一份邮件:

Dear Dinesh ,

Tks for your reply!

I try to post the problem at bbs as your give,but nobody rebply(http://community.rtcamp.com/t/website-will-dead-when-we-click-the-button-purge-entire-cache/5052),so send a email to you again...

Certainly,switch to "redis cache" is a good idea. But I use Nginx Fascgi Caching for a long time, because of it's simple. furthermore, redis is not installed on my webserver.

Except for the solution I mentioned in my email. The function of "Purge all cache" should be hiddenwhen then plugin used Nginx-Fascgi-caching and set with "Delete local server cache files " method. Only in this way, the problem will not be triggered by someone who know nothing about this case.

Of course, This problem should be gone when used "Uses the ngx_cache_purge module"....

Regards, Jager

问题你不解决没关系,但至少应该把这个功能隐藏或加上警告吧?这也是对插件用户负责的表现,否则很多不知情的人一点击一键清理后,前台就歇菜了!多么惊恐,谁还敢用。。。。

好了,如果你也存在这个问题,可以参考本文折腾一下。改了半天插件,发现这个插件并不复杂,后续有空自己写几段 PHP 代码就可以替换掉了。


2016-01-24 最新补充:突然想明白了一件事,其实一键清理可以不出现本文提到的问题!那就是定义 nginx 缓存路径是最多使用两级目录,而不能多于两级。

比如,我之前的文章定义的 Nginx 缓存目录都使用了 /tmp/cache/wpcache,这种就是多于两级目录了,Nginx-Heper 删除的时候会直接删除这个路径,如果不重载 Nginx 就不会重新生成目录结构,将导致网站打不开!

简单分析原因,应该是类似于 mkdir 是否带 -p 参数的结果,如果 mkdir 要创建多级目录,中间目录不存在时必须加入 -p 才能成功创建!类比到 Nginx 的缓存,它就没有用到 -p 这种机制,如果多级目录,中间目录不存在,它就傻眼了!

如果是定义成一级或二级目录,比如使用 /tmp/wpcache 就不会出现这个问题,具体原因就不做分析了!大家如果参考了张戈博客之前写的 Nginx 缓存配置,请将缓存文件的路径都修改为二级即可,比如 /tmp/wpcache 。

28 条回应
  1. 老杨 2015-8-30 · 1:00

    暂时用不上,话说你这个相关文章在手机端的样式不错,自己改的?还是以前版本是这个样子的?我那个新版本的比较丑,太大了。

    • avatar
      Jager 2015-8-30 · 10:48

      估计是鸟哥改版就改成你们现在这样子了,我有几个版本没更了。。

      • 老杨 2015-8-30 · 11:58

        嗯,不知道还会不会有啥重大更新,没有的话我也想折腾了。

  2. 小幻 2015-8-30 · 7:38

    略高大上,十一的时候再折腾下

  3. 蓝染君 2015-8-30 · 8:54

    博主你好,我的站用了你站的nginx fastcgi_cache 技术 效果不错自己又安装了pagespeed加速,话说这两款有先后顺序吗?是先缓存还是先加速?给个建议吧,加你Q也不行,另外我点的就是后台啊,没有出现你说的现象!

  4. 微商货源吧 2015-8-30 · 23:58

    想搞,但是不懂 :shock:

  5. god 2015-9-1 · 23:03

    一直都有这个问题,一般都是自己restart解决。楼主这样改以后 每次回复都会重启nginx?

    • avatar
      Jager 2015-9-1 · 23:18

      那不叫重启,而是重载,不影响访问。俗称平滑重启nginx 使用 -s reload 参数,自己百度脑补一下。

  6. wordpress优化 2015-9-2 · 16:23

    我一直用这哥们的这个插件,就是像他建议的那样,用了redis,所以没有出现这个问题

    • 微协助 2017-2-11 · 22:36

      你好 请问你 启用redis配置 缓存文件的选项那里怎么填写的?自己手动设置的么?

  7. 科研动力 2015-9-2 · 20:50

    对于这种自我解决问题的人,我是很佩服的

  8. 朱海涛自媒体 2015-9-3 · 15:53

    过来看看,支持一下

  9. 牧羊人 2015-9-4 · 19:46

    用不上~

  10. 烂番茄 2015-9-12 · 13:40

    现在我都很少用缓存了哈。。

  11. BigChicken 2016-4-30 · 0:52

    按照你的 fascgi_cache 配置,我的也出现了和你一样的问题
    后来发现把 fastcgi_cache_path fastcgi_temp_path
    两个参数设置成同一个级别的目录而不是某个是某个的子目录,purge all cache 一切ok。

    • avatar
      Jager 2016-4-30 · 10:18

      文章后面的最新补充已经分享了

    • 微协助 2017-2-12 · 22:40

      请问你用的php版本是多少? 我目前测试发现应该不支持php7.1

  12. Qa 2016-7-28 · 3:11

    还有个问题,不知道注意到没有。
    这个插件对于AJAX提交的评论无法识别刷新缓存。好困扰 :sad:

  13. 采觅随记 2016-9-7 · 10:35

    运维笔记的这个教程中建议将fastcgi_cache_path设置tmpfs内存中,centos默认/dev/shm路径,故会造成这样的“/dev/shm/nginx-cache”的三级目录,就会导致本文问题。如果把/tmp目录挂载到tmpfs,这样是不是可以即能让fastcgi_cache_path二级目录,又可以放到内存加速 :grin:
    系统默认应该是不会把/tmp目录挂载到tmpfs,手动挂载操作可参考如下:
    【centos6】http://blog.jjonline.cn/linux/139.html
    【centos7】http://www.linuxidc.com/Linux/2015-06/118787.htm
    记得重启输入df -h命令看看是否成功挂载哦!

    • avatar
      Jager 2016-9-7 · 22:09

      很多vps的tmpfs只有几百兆。。。

      • 采觅随记 2016-9-7 · 22:17

        有资料说tmpfs默认是内存一半,但是需要多少占用多少,动态调节会根据需要变大,内存不够时会使用占用SWAP(如果有)。一般个人站我觉得可以用用吧 :mrgreen: ,运维笔记博主他1核1G应该也这样的。

        • avatar
          Jager 2016-9-7 · 22:22

          够用的话是可以,实际上不是在访问量特别大的环境,效果并不明显。静态过后的瓶颈主要在于公网带宽

          • 采觅随记 2016-9-7 · 22:37

            :???: 好吧,你说到大多数站长的心坎了

          • 微协助 2017-2-12 · 22:54

            硬盘够烂 内存多的情况下 放内存合适,然后带宽就是关键了 :lol:

  14. 微协助 2017-2-9 · 1:20

    你好博主,你说的这个问题我真的碰到了。。作为一个萌新我真的用力在按照教程一步步设置成功,
    只要一启用这个插件后 我的网站立刻502了 。真心给跪了,而且我的缓存目录就是二级的。。然后百度了很久没解决 你看能提供点帮助么!谢谢 :sad:

  15. 微协助 2017-2-11 · 23:57

    Jager同学还没回复啊,,我还在排查问题,想请问你的服务器软件配置的情况 参考,
    我出现问题的环境是debian7 x64' php7.1我在想是不是这个插件不支持7.1 而且我开启了bbr,要更换内核,目前排查出来就剩下这两个了 我去试试,

  16. 微协助 2017-2-12 · 22:38

    Jager同学 我研究回来了。。有几个疑问,配置的缓存目录可以自己随意定义是在内存还是data硬盘么?因为我测试发现缓存目录里面并没有任何文件,还有一个问题 没确定,Nginx Helper 这个插件或者fastcgi_cache模块不支持php7.1,当我启用7.0版本时没有出现502错误,而我切换到7.1后登陆的用户可以访问,没有登陆的用户打不开网站,甚至连错误代码都不提示,比如502,Nginx-helper纯代码版也实验了一样如此,暂时判断为fastcgi_cache不支持php7.1

    • avatar
      Jager 2017-2-13 · 19:01

      本文插件早已弃用,用纯代码随便你自己改:https://zhang.ge/5112.html