Nginx 启用 FastCGI_Cache 将 WordPress 静态化缓存加速

2 Comments

一年前曾经折腾过 FastCGI_Cache 缓存加速 WordPress,无奈没上线多久,发现 FastCGI_Cache 会把评论者信息和登陆信息缓存,不知道怎么处理掉,只好下线,后来没再折腾。

简介

目前在用 Memcached 数据库缓存,主题做好缓存,数据库查询可以大大减少,一定程度上减少服务器压力,提点速度。提升很大?有什么缺点?其实对于这个访问量不大,服务器在国外的小博客来说,就是聊胜于无吧。

最近想换一个缓存试试,打算用 redis 替换掉 Memcached,看人家OpenResty + Redis 方案不错,琢磨着找时间切换过去。在 DG 上开了个测试机器,试了一圈,还是折中方案(Nginx + Redis Cache)更方便折腾。

然而测试时发现,Redis 会与 FastCGI_Cache 一样把评论者信息和登陆信息缓存,既然最终结果差不多,那还不如直接用 Nginx 内置的 FastCGI_Cache?这样可以省去安装 redis,以及相关几个 nginx 扩展。

Nginx 内置 FastCGI_Cache 缓存,但是不支持自动清除缓存。在 WordPress 新建/修改文章,或者访客提交评论,都不会自动清空相关缓存!Nginx 安装 ngx_cache_purg 扩展 + WordPress 缓存清理插件 Nginx Helper 可以解决这个问题。

安装 ngx_cache_purge

检查是否已安装 ngx_cache_purge

nginx -V 2>&1 | grep -o ngx_cache_purge

一般都不会安装,如果显示 ngx_cache_purge 则已安装。

编译安装 nginx_cache_purge

两种方法:一是基于 OneinStack 升级脚本升级 nginx 把扩展编译进去;而是查看原本编译参数,加上 ngx_cache_purge 直接编译。

基于 OneinStack 升级脚本偷懒方法

下载、解压 ngx_cache_purge 安装包:

cd /root/oneinstack/src
wget --no-check-certificate -c -O ngx_cache_purge-2.3.tar.gz https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz
tar xzf ngx_cache_purge-2.3.tar.gz
cd /root/oneinstack

修改 OneinStack nginx 升级脚本:

nginx_modules_options 中增加扩展配置,在 oneinstack/include 目录,找到 upgrade_web.sh,将 ./configure ${nginx_configure_args} 修改为:

./configure ${nginx_configure_args} --add-module=../ngx_cache_purge-2.3

执行脚本升级 Nginx:

~/oneinstack/upgrade.sh

选择升级 nginx,输入需要升级的版本号。

直接加参数编译

cd /root/oneinstack/src
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
wget http://nginx.org/download/nginx-1.17.5.tar.gz
tar xzf ngx_cache_purge-2.3.tar.gz
tar xzf nginx-1.17.5.tar.gz
cd nginx-1.17.5
nginx -V #查看 nginx 编译参数,最后加上--add-module=../ngx_cache_purge-2.3
./configure --prefix=/usr/local/nginx --user=www --group=www \
--with-http_stub_status_module --with-http_v2_module --with-http_ssl_module \
--with-ipv6 --with-http_gzip_static_module --with-http_realip_module \
--with-http_flv_module --with-ld-opt=-ljemalloc \ # 蓝色部分为你网站当前编译参数,请根据实际修改
--add-module=../ngx_cache_purge-2.3
make  #编译
mv /usr/local/nginx/sbin/nginx{,_`date +%F`}  #备份nginx
cp objs/nginx /usr/local/nginx/sbin
nginx -V 2>&1 | grep -o ngx_cache_purge
# 显示ngx_cache_purge表示已经安装成功

参考资料:LinuxEye,LNMP 安装可以参考旧文

配置 FastCGI_Cache

fastcgi_cache_path 放到 tmpfs 内存中,比放在硬盘上更快。CentOS 目录在 /dev/shm,Ubuntu 和 Debian 在 /run/shm。使用 df -h /var/run 命令查看空间大小。

创建缓存目录

比如,在 run/ 目录下创建 nginx-cache

mkdir -p  /var/run/nginx-cache

修改网站配置文件

下面为实例,蓝色字体部分请根据实际修改。

#如果缓存多站点则把下面四行放到nginx.conf 中 
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:192m inactive=1d;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;


server {
listen 80;
listen 443 ssl http2;
ssl_certificate /usr/local/nginx/conf/ssl/cyhour.com.crt;
ssl_certificate_key /usr/local/nginx/conf/ssl/cyhour.com.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_buffer_size 1400;
add_header Strict-Transport-Security max-age=15768000;
ssl_stapling on;
ssl_stapling_verify on;
server_name cyhour.com www.cyhour.com;
##access_log /data/wwwlogs/cyhour.com_nginx.log combined;
access_log /data/wwwlogs/cyhour.com_nginx.log main;
index index.html index.htm index.php;
root /data/wwwroot/cyhour.com;
if ($ssl_protocol = "") { return 301 https://$host$request_uri; }
if ($host != cyhour.com) { return 301 $scheme://cyhour.com$request_uri; }
include /usr/local/nginx/conf/rewrite/wordpress.conf;
#error_page 404 /404.html;
#error_page 502 /502.html;

set $skip_cache 0;
set $skip_cache 0;

# POST 和带参数的请求不展示缓存
if ($request_method = POST) {
set $skip_cache 1;
}
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;
}

# 登录用户和评论过的用户不展示缓存
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}


location ~ [^/]\.php(/|$) {
#fastcgi_pass remote_php_ip:9000;
fastcgi_pass unix:/dev/shm/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;

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;

}

include custom.conf;

location ~ /purge(/.*) {
allow 127.0.0.1;
allow 1.1.1.1;#此处为服务器公网IP地址
deny all;
fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
}


location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
#expires 30d;
#access_log off;
expires max;
}

location ~ .*\.(js|css)?$ {
expires 7d;
access_log off;
}
location ~ /\.ht {
deny all;
}
}

我这里把「# 登录用户和评论过的用户不展示缓存」部分注释掉了,所有用户看到的都是缓存。另外,不需要缓存的重定向规则,需要放到「# 指定页面不展示缓存」之后,否则排除缓存规则无法生效。

比如,老杨把 /go/ 外链跳转目录设置为不缓存,include custom.conf; 里面有跳转规则 rewrite ^/go/(.*)$ /ooxx/xxooxxoo.php?oox=$1 last;,那么 一定要把 include custom.conf; 放到「# 指定页面不展示缓存」之后,否则 /go/ 还是会被缓存。(亲测)

使 nginx 配置生效

nginx -t 先检查一下配置,确认无误,重启 nginx

service nginx reload

安装 Nginx Helper 插件

前面说过 FastCGI_Cache 不支持自动清除,WordPress 可以安装 Nginx Helper 插件通过 nginx_cache_purge 接口自动清理缓存。

后台搜索 Nginx Helper 插件,安装,激活,Enable Purge,Caching Method 选 nginx Fastcgi cache (requires external settings for nginx),其余使用默认配置即可。

点击查看 Nginx Helper 配置

插件作者定义缓存路径是 /var/run/nginx-cache ,如果自定义缓存路径,可能会导致插件无法找到缓存文件删除!

解决办法是在 WordPress 根目录下 wp-config.php 中新增如下代码即可:

//根据实际情况定义缓存的存放路径
define( 'RT_WP_NGINX_HELPER_CACHE_PATH','/tmp/wpcache');

如果上述定义路径代码不生效,可以试试使用软连接:

ln -s /var/run/nginx-cache  /tmp/wpcache

如不想使用插件,可以使用 Nginx Helper 纯代码版

检查 FastCGI_Cache 是否正常工作

打开网页,F12 打开开发者工具,查看 HTTP 的响应头部,可以看到 x-cache 状态。

 1189-fastcgi_cache_status

HIT 代表命中缓存
MISS 代表没有找到缓存
BYPASS 代表跳过缓存
EXPIRED 代表缓存过期

还可以刷新站点,看缓存目录是否增大。

du -sh /var/run/nginx-cache

温馨提示:开启 FastCGI_Cache 需谨慎!!!上线前需先测试,修改主题解决以下两个问题:1.fastcgi_cache 可能会缓存评论者名称和邮箱信息;2.如果在登陆状态回复评论,会缓存登陆界面。

修改 WordPress 主题匹配 FastCGI_Cache 静态化缓存

静态化缓存,可能会带出一些问题,比如前面说的,FastCGI_Cache 可能会缓存评论者名称和邮箱信息;如果在登陆状态回复评论,会缓存登陆界面;WP-PostViews 不计数……下面记录一下折腾过程,有需要参考一下。

WordPress 让管理员在前台匿名以避免CDN/静态缓存

作者:成航先森,这个可以避免把管理员访问网页被缓存。(其实前面规则按道理就不会缓存登录用户以及已知评论者,不过去年折腾时实测确实是会缓存)

/*
** 让管理员在前台访问匿名
** http://www.capjsj.cn/make_known_users_anonymous.html
*/
function make_known_users_anonymous() {
global $current_user;
if(!is_admin() && $_GET['preview'] != 'true'){
$current_user = array(
'user_login' => '',
'user_email' =>'',
'user_level' => '',
'user_firstname' => '',
'user_lastname' => '',
'display_name' => '',
'ID' => '',
'user_url' => '',
);
}
return $current_user;
}
add_action( 'init', 'make_known_users_anonymous' );

主题评论框表单修改

ajax 提交评论部分可能会有设置 cookies 记住评论者信息代码:

$user = wp_get_current_user();
do_action('set_comment_cookies', $comment, $user);

亲测,把这两行注释掉,对所有用户缓存情况下,还是会把评论者信息缓存,展示给其他用户。

因为评论表单代码可能这样子:

<div id="comment-author-info">
<p class="comment-form-author">
<input type="text" name="author" placeholder="昵称<?php if ($req) echo "(必填)"; ?>" id="author" class="commenttext" value="<?php echo $comment_author; ?>" tabindex="1" />
</p>
<p class="comment-form-email">
<input type="text" name="email" placeholder="邮箱<?php if ($req) echo "(必填)"; ?>" id="email" class="commenttext" value="<?php echo $comment_author_email; ?>" tabindex="2" />
</p>
<p class="comment-form-url">
<input type="text" name="url" placeholder="网址" id="url" class="commenttext" value="<?php echo $comment_author_url; ?>" tabindex="3" />
</p>
</div>

把表单中 value="<?php echo $comment_******; ?>" 直接删除或者改成 value="" 也许就好了。

浏览数不更新

页面静态化后,原本 php 统计浏览数会失效,导致浏览数不更新。解决方法:CDN后用Ajax动态提交、显示文章阅读量,cookies避免重复刷新

注:目前在用 WP-Postviews(文章浏览数)代码精简版

在 footer.php 中添加 ajax 代码

注意需要将前台显示访问量标签 ID 或 class 名称须与主题匹配。

<?php 
if( defined( 'FastCGI_Cache' ) && FastCGI_Cache ): // CDN、开缓存wp-config.php开启缓存 ?>
<script type= "text/javascript" >
//http://cn.voidcc.com/question/p-rymvrgdr-rc.html
function intlFormat(num) {
return new Intl.NumberFormat().format(Math.round(num*10)/10);
}
function makeFriendly(num) {
if(num >= 1000000)
return intlFormat(num/1000000)+'M';
if(num >= 1000)
return intlFormat(num/1000)+'k';
return intlFormat(num);
}
function GetCookie(sName) {
var arr = document.cookie.match(new RegExp("(^| )"+sName+"=([^;]*)(;|$)"));
if(arr !=null){return unescape(arr[2])};
return null;
}
var postviews_cook=GetCookie("postviews-<?php the_ID();?>");
if ( postviews_cook == null ){
jQuery.ajax({ type:'POST', url: "<?php echo admin_url('admin-ajax.php');?>" , data:"postviews_id=<?php the_ID();?>&action=postviews",
cache:false,success: function(postviews_count){ jQuery("#main #post-<?php the_ID();?> .views").text('Views:' + makeFriendly( postviews_cook ) );document.cookie="postviews-<?php the_ID();?>=" + postviews_count;} });
} else {
jQuery("#main #post-<?php the_ID();?> .views").text('Views:' + makeFriendly( postviews_cook ) );
};
</script>
<?php endif; ?>

主题 functions.php 添加代码

if( defined( 'FastCGI_Cache' ) && FastCGI_Cache ){ // CDN、开缓存wp-config.php开启缓存
/*
* 缓存时更新浏览量-有缓存
* http://www.capjsj.cn/ajax_cookies_views.html
*/
function postviews_cache(){
if( empty( $_POST['postviews_id'] ) ) return;

$post_ID = $_POST['postviews_id'];
if( $post_ID > 0 ) {
$post_views = (int)get_post_meta($post_ID, 'views', true);
update_post_meta($post_ID, 'views', ( $post_views + 1 ));
echo ( $post_views + 1 );
exit();
}
}
add_action( 'wp_ajax_nopriv_postviews', 'postviews_cache' );
add_action( 'wp_ajax_postviews', 'postviews_cache' );
}

修改 wp-config.php 配置

加入下面代码,然后重启 php 即可:

define('FastCGI_Cache', true);

如使用 WP-Postviews 插件,wp-config.php 中,加入下面这行代码:

define('WP_CACHE', true);

然后在 WP-Postviews 插件选项中启用「使用 AJAX 更新浏览量」即可。

js 记住评论者信息

前面一顿操作,如无意外,WordPress 已经记不住评论用户信息。访客每次评论都需要填写信息,虽然可以「一键填写评论中用户信息」,但是多个自动记住信息可能会更方便。

解决方法:WordPress记住评论用户信息的js版本,直接操作cookie无视缓存解决JS操作Cookies出现的乱码问题,修复WordPress评论乱码

代码

//设置Cookie
function SetCookie(sName, sValue,iExpireDays) {
if (iExpireDays){
var dExpire = new Date();
dExpire.setTime(dExpire.getTime()+parseInt(iExpireDays*24*60*60*1000));
document.cookie = sName + "=" + escape(sValue) + "; expires=" + dExpire.toGMTString()+ "; path=/;domain=.cyhour.com";
}
else{
document.cookie = sName + "=" + escape(sValue)+ "; path=/;domain=.cyhour.com";
}
}
// 目的: 返回Cookie
function GetCookie(sName) {
var arr = document.cookie.match(new RegExp("(^| )"+sName+"=([^;]*)(;|$)"));
if(arr !=null){return unescape(arr[2])};
return null;

}
//加载用户信息
function LoadRememberInfo() {
var strName=GetCookie("author");
var strEmail=GetCookie("email");
var strHomePage=GetCookie("url");
var bolRemember=GetCookie("chkRemember");
var a_vlaue= document.getElementById("author");
if (a_vlaue != null){
if(bolRemember=="true"){
//通过decodeURIComponent对内容解码
if(strName){document.getElementById("author").value=decodeURIComponent(strName);};
if(strEmail){document.getElementById("email").value=strEmail;};
//通过decodeURIComponent对内容解码
if(strHomePage){document.getElementById("url").value=decodeURIComponent(strHomePage);};
if(bolRemember){document.getElementById("saveme").checked=bolRemember;};
}

if(GetCookie("username")){
document.getElementById("author").value=unescape(GetCookie("username"));
}
}
}
//通过jQuery ready在页面加载时自动从cookies中载入已保存的用户信息
jQuery(document).ready(function($){
LoadRememberInfo();
//给评论提交按钮绑定信息保存函数
$("#respond #submit").click(function(){
SaveRememberInfo();
});
//给评论重置按钮绑定信息移除函数
$("#respond #reset").click(function(){
RemoveRememberInfo();
});
});
//保存信息函数
function SaveRememberInfo() {
var strName=document.getElementById("author").value;
var strEmail=document.getElementById("email").value;
var strHomePage=document.getElementById("url").value;
var bolRemember=document.getElementById("saveme").checked;
//通过encodeURIComponent对内容进行url编码
SetCookie("author",encodeURIComponent(strName),365);
SetCookie("email",strEmail,365);
//通过encodeURIComponent对内容进行url编码
SetCookie("url",encodeURIComponent(strHomePage),365);
SetCookie("chkRemember",bolRemember,365);

}
//移除信息函数
function RemoveRememberInfo() {
SetCookie("author",'',365);
SetCookie("email",'',365);
SetCookie("url",'',365);
SetCookie("chkRemember",'false',365);
}

代码中有两处 domain=.cyhour.com,一定要更改成自己博客域名。

将代码加入到 WordPress 主题 js 文件中即可,比如加入到 comments-ajax.js 最后。如果没有 ajax 评论,就没有 comments-ajax.js,可以将代码保存为 saveinfo.js ,然后引入即可。

修改 comments.php

编辑主题 comments.php 文件,找到提交留言按钮代码,在合适位置添加勾选框:

<input type="checkbox" id="saveme" value="saveme" checked="checked" title="记住我,下次回复时无需重新输入个人信息。" /><label for="comment_mail_notify">记住我</label>

添加后代码,仅供参考,需根据实际修改:

....以上省略....
<p class="form-submit">
<input type="checkbox" id="saveme" value="saveme" checked="checked" title="记住我,下次回复时无需重新输入个人信息。" /><label for="comment_mail_notify">记住我</label>
<input id="submit" name="submit" type="submit" tabindex="5" value="发表留言(Ctrl+Enter)"/>
<?php comment_id_fields(); do_action('comment_form', $post->ID); ?>
</p>
....以下省略....

WordPress 回复评论自动添加@评论者

作者:露兜

这个非必需,我这里启用 444 级评论嵌套,不过只显示 2 级,不加上@评论者,有时候可能不知道谁回复谁。原本是 js 代码添加,原本担心让管理员在前台匿名后,管理员无法在前台回复评论,而原本 js 添加 @ 功能后台回复无效,于是换上这个。

在当前主题 functions.php 中添加以下代码(会直接将 @ 信息写入数据库):

// 评论添加@,by Ludou
function ludou_comment_add_at( $commentdata ) {
if( $commentdata['comment_parent'] > 0) {
$commentdata['comment_content'] = '@<a href="#comment-' . $commentdata['comment_parent'] . '">'.get_comment_author( $commentdata['comment_parent'] ) . '</a> ' . $commentdata['comment_content'];
}

return $commentdata;
}
add_action( 'preprocess_comment' , 'ludou_comment_add_at', 20);

如果你不想将 @评论者 写入数据库,可以使用下面的代码:

// 评论添加@,by Ludou
function ludou_comment_add_at( $comment_text, $comment = '') {
if( $comment->comment_parent > 0) {
$comment_text = '@<a href="#comment-' . $comment->comment_parent . '">'.get_comment_author( $comment->comment_parent ) . '</a> ' . $comment_text;
}

return $comment_text;
}
add_filter( 'comment_text' , 'ludou_comment_add_at', 20, 2);

卸载 Memcached

Memcached 是数据库缓存,一般开启 FastCGI_Cache 静态化缓存,Memcached 基本上就没太大作用,与 FastCGI_Cache 一样,第二次访问才缓存。

结束进程并取消开机启动:

killall memcached && chkconfig memcached off && chkconfig --del memcached

查找所有 Memcached:

find / -name memcached

然后删除掉,比如:

rm -rf /run/memcached /run/lock/subsys/memcached /usr/bin/memcached /usr/local/memcached /usr/local/memcached/include/memcached /usr/local/memcached/bin/memcached /etc/rc.d/init.d/memcached /var/spool/mail/memcached

后记:重新安装上 Memcached

虽然大部分内容已经静态缓存,但还是有部分没有缓存,Memcached 还是有点用处。

OneinStack 安装 Memcached 以及 php-memcached 扩展:

cd /root/oneinstack
./install.sh --memcached
./install.sh --php_extensions memcached

使用方法参考:WordPress 启用 Memcached 动态缓存

参考资料

-- 完 --

除非注明,常阳时光文章均为原创,本文地址 https://cyhour.com/1189/ 转载时必须以链接形式注明原始出处。
Vultr 送$25,搬瓦工年付最低$49,优惠码 BWH34QMFYT2R,更多推荐VPS信息,或支持老杨
Views: 168 Tags:  ,  ,  ,  ,  ,  , 

Comments:2

  1. 我也折腾过,后来还是还原了。感觉不怎么好用。

    2019.10.30 16:01 # 回复
    1楼

发表留言

Vultr 送$25,搬瓦工年付最低$49,优惠码 BWH34QMFYT2R,更多推荐VPS信息