FastCGI 快取网站加速,Nginx Helper 特别加强版本

Nginx 里用来处理 PHP-CGI 运作需求的模块 ,其中有一个说他鸡肋但又真能加速的快取功能叫「FastCGI Cache」。ngx_http_fastcgi_module

鸡肋的点是因为他就只会「照你的方式」快取,但要删除它... 就请自理,整个很工程(难)。

所以要处理它会分两个部分「设置快取逻辑」与「设置对应删除逻辑」。

Google 等关键词可以找到一堆差不多的教学,这边标题写特别版就是真的跟大部分介绍文章不同。NginxFastCGI Cache快取WordPress

网络上的文章千篇一律都是教同一个设定快取的方式,然后 WordPress 端搭配 Nginx Helper 外挂来做清除。

但那样的使用情境有一个前提:你的网站是 RWD 响应式设计且不会因为设备不同而有后端运算处理数据的不同。

这样一来只需要把网页快取着一份,清理的时候也只需要清理一份就好了!

但是,如果我的 WordPress 网站使用了双主题架构或是特别处理,导致在手机或平板浏览下是 A 主题,电脑版则是 B 主题时,只快取其中一份都不对吧?

简单来说,同一个网址如果因为设备请求不同而有不同呈现的话,原本默认快取方式就有问题。

设定缓存逻辑

这边要先谈一下FastCGI快取运作的机制,这功能宣告使用一个空间与限制大小后,透过设定一组来做加密且把快取数据存在那空间里。keymd5

fastcgi_cache_key "$scheme$request_method$host$request_uri";

这组 通过几个参数组合来达到独特性,结构就跟网址差不多,结果如下:keyhttpsGETwpmore.cn/

FastCGI 模块将上述示例 加密后得到 这个缓存文件名,并把缓存数据(网站页面源代码)存放于指定特殊路径下。key6feae0f210b851e9fb54f21440aaf6c0

特殊路径的规则也很简单,取上述加密文件名的后三码为路径文件夹,最后 1 码为第一层,最后第 2 与第 3 为第二层。 所以假设我指定存放快取的根路径是 的话,那这份快取就存在 这里。md5 /tmp/nginx-cache/ /tmp/nginx-cache/0/6c/6feae0f210b851e9fb54f21440aaf6c0

看到这就会发现,如果还要区分手机版或电脑版的话,还要让 Nginx 帮忙判断一下 请求来源。User Agent

map $http_user_agent $is_desktop {
    default 0;
    ~*linux.*android|windows\s+(?:ce|phone) 0; # exceptions to the rule
    ~*spider|crawl|slurp|bot 1; # bots
    ~*windows|linux|os\s+x\s*[\d\._]+|solaris|bsd 1; # OSes
}

## Revert the logic.
map $is_desktop $is_mobile {
    1 0;
    0 1;
}
add_header x-ua-device $is_mobile;

Gist 来源

所以原本的 就要更新成:key

fastcgi_cache_key "$scheme$request_method$host$request_uri$is_mobile";

让请求来源不同,就建立不同的快取版本!

所以主要差异就如上所说,下方把设定统整一下:

http{

[略]

map $http_user_agent $is_desktop {
    default 0;
    ~*linux.*android|windows\s+(?:ce|phone) 0; # exceptions to the rule
    ~*spider|crawl|slurp|bot 1; # bots
    ~*windows|linux|os\s+x\s*[\d\._]+|solaris|bsd 1; # OSes
}

## Revert the logic.
map $is_desktop $is_mobile {
    1 0;
    0 1;
}
add_header x-ua-device $is_mobile;
fastcgi_cache_path /tmp/nginx-cache levels=1:2 keys_zone=WORDPRESS:256m inactive=1d;

[略]

server {
[略]

#設定是否略過快取的開關,0是不略過
set $skip_cache 0;
#POST請求一率略過
if ($request_method = POST) {
    set $skip_cache 1;
}
#有傳GET參數的也略過,避免問題一堆與不好清除快取
if ($query_string != "") {
    set $skip_cache 1;
}

#指定的頁面略過
if ($request_uri ~* "/wp-admin/|/go/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
    set $skip_cache 1;
}

#判斷 cookie 登入用戶也略過快取
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
    set $skip_cache 1;
}

#正在維護模式中也略過
if (-f "$document_root/.maintenance") {
    set $skip_cache 1;
}

[略]

location ~ [^/]\.php(/|$) {
    fastcgi_pass  unix:/tmp/php-cgi.sock;
    fastcgi_index index.php;
    include fastcgi.conf;
    include pathinfo.conf;
    fastcgi_cache_key "$scheme$request_method$host$request_uri$is_mobile";
    fastcgi_cache_use_stale error timeout invalid_header http_500;
    fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    add_header X-Cache "$upstream_cache_status From $host";
    fastcgi_cache WORDPRESS;
    fastcgi_cache_valid  200 301 302 1d;
}

[略]
}
}

设置好记得 验证,没有问题后就重新装入设置,通过 Chrome 浏览器开发者工具验证不同设备请求页面,且服务器响应的 Header 有没有看到 。nginx -tx-cache: HIT From 你的網域

这边的需求网络上也有看到一篇讨论:How to - Fastcgi_cache & Desktop with Mobile versions - Purging with GET Requests 可以参考。

如果上述没问题的话就要进行到清除的部分。

设定对应删除逻辑

其实删除的逻辑上面已经提到,只是改由 WordPress 这边再实现一次。 流程就是把网站上要清除缓存的链接,使用FastCGI设置的组成方法,重组回那个加密的文件名,然后使用PHP的方法移除该缓存文件就删除完成了!key md5

网络上大家推的 Nginx Helper 外挂很可惜没有办法通过设定的 hook 来去实现本篇说的情境。 架构上还要调整,以及也还有点问题要修。

所以我就把这款外挂中FastCGI快取清除的部分抽离与修改,发布了一套纯用在清除Nginx FastCGI快取的外挂:Nginx FastCGI Cache清除小帮手

刚写出来,还没整理,就是一个能用的版本。 设置缓存路径的常数沿用 Nginx Helper,默认值则是改成我用的 。RT_WP_NGINX_HELPER_CACHE_PATH/tmp/nginx-cache

如使用上碰到 BUG,欢迎开 issue ~

后记

其实网络上还会补上一个 Nginx 模组「」,使用 API 请求方式来删除快取,尽管 FRiCKLE 的版本表示已达可商用等级,不过超过五年没更新,放着 issue 没想解,我就挑了 torden 的 版分支(2020/01 释出)来试试,除了 功能一直试不出来,其他都正常在 Nginx/1.16.1 版本下运作。ngx_cache_purge v2.3.1 purge_all

重新编译 Nginx 时补上 --add-module=/path/to/src/ngx_cache_purge-2.3.1 即可

但!! 如果能在执行 PHP 的时候顺便删除档案,为何还要绕一个 URL API 「再」请 Nginx 来删呢? 所以这也是我外挂不打算实作这种清除快取方式的原因。

其他像是把这类似机制套上 Redis 的 SR Cache 就改天有时间再来测试了,毕竟简单有效就能处理的才讨喜呀XD

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注