首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >WordPress 的四层缓存分别解决哪种慢,按什么顺序配(附可跑的 Nginx 与 WP-CLI 步骤)

WordPress 的四层缓存分别解决哪种慢,按什么顺序配(附可跑的 Nginx 与 WP-CLI 步骤)

原创
作者头像
用户10345225
发布于 2026-10-25 15:07:39
发布于 2026-10-25 15:07:39
1740
举报

四层缓存堵的是四个不同位置的等待。顺序配错,会出现两种典型结果:加了一堆缓存但页面还是慢,或者后台改了内容前台还是旧的。

建议的顺序:

  1. 先测基线,不测就没法判断哪一层真的有用
  2. 浏览器缓存——只改响应头,风险最低
  3. CDN——先只接静态资源,HTML 等第 3 步之后再说
  4. 页面缓存——整页 HTML,收益最大,但要处理排除规则
  5. 对象缓存——需要额外的 Redis 或 Memcached 服务,收益最局部

例外:登录用户占比高的站(电商、会员站、论坛)把对象缓存提到页面缓存前面。这类请求基本都会被页面缓存排除掉,先上页面缓存拿不到多少收益。

为什么前两层排在前面:它们不动 PHP、不动数据库,只改响应头和分发路径,配错改回去就行;而且它们决定了后面两层的效果能不能被用户感知到——源站再快,用户隔着半个地球访问一样慢。

四层各治哪种慢

层

命中时省掉什么

收益落在谁身上

生效位置

浏览器缓存

重复下载同一个 CSS / JS / 图片

回访用户、站内跳转

用户设备

CDN

用户到源站那段网络往返

异地用户

边缘节点

页面缓存

PHP 执行 + 查库 + 拼 HTML 整段

未登录访客

源站

对象缓存

单次请求里重复的同一份查询

未命中页面缓存的请求、登录用户

源站内存

配错的典型症状:

现象

多半是

首字节很快,图片慢慢刷出来

只做了页面缓存,没做 CDN

回访用户每次都重新下载 CSS

没设 Cache-Control,或资源 URL 没有版本参数

后台改了价格,前台还显示旧的

页面缓存或 CDN 缓存了 HTML,没有失效机制

加完购物车页面变成「未登录」版本

页面缓存没排除带 cookie 的请求

上了对象缓存,TTFB 没变化

页面缓存命中率高,请求根本没走到 PHP

Step 0:先测基线

代码语言:bash
复制
for i in 1 2 3 4 5; do
  curl -o /dev/null -s -w 'ttfb:%{time_starttransfer} total:%{time_total}\n' https://example.com/
done

跑五次,丢掉第一次(TCP、TLS 握手会拖高),看后四次的 time_starttransfer。后面每做完一层,用同一条命令再跑一次对比。没有这个数,后面所有判断都是感觉。

Step 1:浏览器缓存

原理一句话:让浏览器自己把文件存下来,下次访问不再问服务器。前提是文件名或 URL 带版本参数,否则你改了文件,用户看到的还是旧的。

代码语言:nginx
复制
server {
    # 加在已有的 server 块里
    location ~* \.(css|js|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf)$ {
        add_header Cache-Control "public, max-age=2592000" always;
        access_log off;
        try_files $uri =404;
    }
}

一个必须知道的坑:add_header 在 location 里会覆盖从上层继承下来的所有 add_header。如果 server 块里还有别的响应头(安全头之类),要在这个 location 里重复写一遍,否则它们会在这个 location 里消失。

WordPress 的 wp_enqueue_style() / wp_enqueue_script() 默认会带 ?ver=,文件改了参数就变,缓存自然失效。主题里手写 <link> 的没有这层保护,改版之后要自己改文件名或者加参数。

验证:

代码语言:bash
复制
curl -sI https://example.com/wp-content/themes/your-theme/style.css | grep -i cache-control

输出里有 max-age=2592000 就对了。

Step 2:CDN

CDN 治的是距离:源站在一个地方,用户在另一个地方,每个请求都得跑一趟。它不管你源站多快,只管少跑路。

先只接静态资源,HTML 的缓存不要现在开。 HTML 里带着价格、库存、登录状态,边缘节点分不清这次请求该给谁,缓存了就是事故。

要设置的三件事:

  1. 回源 Host 指向你的域名,不要填 IP。Host 不匹配时 WordPress 会跳转或生成错误链接。
  2. 静态资源的边缘 TTL 跟着上一步的 Cache-Control 走,不要另设一套,否则两边打架,排查起来很痛苦。
  3. 静态资源回源时去掉 cookie(图片不需要),能提高命中率;页面请求的 cookie 要透传。

验证:

代码语言:bash
复制
curl -sI https://example.com/wp-content/uploads/2026/01/pic.jpg | grep -i age
sleep 3
curl -sI https://example.com/wp-content/uploads/2026/01/pic.jpg | grep -i age

第二条的 age 应该比第一条大,说明命中的是边缘节点而不是源站。很多 CDN 还会返回自己命名的命中状态头,看 age 是最通用的办法。

Step 3:页面缓存

这是收益最大的一层:生成一次 HTML 要跑 PHP、查几十次库,缓存下来这些全省了。用 nginx 的 fastcgi_cache 做,不依赖插件,出问题也好定位。

3.1 http 上下文(放到 /etc/nginx/conf.d/ 下任意 .conf)

代码语言:nginx
复制
fastcgi_cache_path /var/cache/nginx/wp levels=1:2 keys_zone=wp_cache:100m max_size=2g inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

# 带这些 cookie 的请求不缓存
map $http_cookie $skip_cookie {
    default 0;
    "~*wordpress_logged_in"       1;
    "~*comment_author"            1;
    "~*wp-postpass"               1;
    "~*woocommerce_items_in_cart" 1;
    "~*woocommerce_cart_hash"     1;
    "~*wp_woocommerce_session"    1;
}

# 只缓存 GET / HEAD
map $request_method $skip_method {
    default 1;
    GET     0;
    HEAD    0;
}

# 这些路径不缓存
map $request_uri $skip_uri {
    default 0;
    "~*/wp-admin/"      1;
    "~*/wp-login\.php"  1;
    "~*/cart/"          1;
    "~*/checkout/"      1;
    "~*/my-account/"    1;
    "~*preview=true"    1;
    "~*[?&]s="          1;
}

# 三个条件拼起来,任何一个为 1 就跳过缓存
map "$skip_cookie$skip_method$skip_uri" $skip_cache {
    default 0;
    "~1"    1;
}

$request_uri 是带查询串的,所以 [?&]s= 能匹配到搜索页。搜索页不缓存是因为参数组合太多,缓存了只会把磁盘塞满。

3.2 server 上下文

代码语言:nginx
复制
location ~ \.php$ {
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    fastcgi_cache wp_cache;
    fastcgi_cache_valid 200 301 302 10m;
    fastcgi_cache_valid 404 1m;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache     $skip_cache;
    fastcgi_cache_lock   on;
    fastcgi_cache_use_stale error timeout updating http_500 http_503;
    fastcgi_cache_background_update on;

    add_header X-Cache $upstream_cache_status always;
}

fastcgi_cache_bypass 和 fastcgi_no_cache 要同时设:前者是不读缓存,后者是不写缓存。只设一个会出现「登录用户看到的内容被写进了公共缓存」。

如果你的 nginx 不认识 fastcgi_cache_background_update,把那一行删掉即可,不影响其他配置。

3.3 建目录、重载、验证

代码语言:bash
复制
# Debian/Ubuntu 是 www-data,CentOS/RHEL 是 nginx
sudo mkdir -p /var/cache/nginx/wp
sudo chown www-data:www-data /var/cache/nginx/wp
sudo nginx -t && sudo systemctl reload nginx
代码语言:bash
复制
curl -sI https://example.com/ | grep -i x-cache   # 第一次:MISS
curl -sI https://example.com/ | grep -i x-cache   # 第二次:HIT
curl -sI -H 'Cookie: wordpress_logged_in_abc=1' https://example.com/ | grep -i x-cache   # 应为 BYPASS

第三条是关键。如果带登录 cookie 还能拿到 HIT,说明你的 map 没生效,线上马上就会出现「A 用户看到 B 用户信息」。

3.4 清页面缓存

代码语言:bash
复制
sudo find /var/cache/nginx/wp -type f -delete

fastcgi_cache_purge 是第三方模块,不是所有 nginx 都编进去了。没装就用上面这条,删文件一样有效。

Step 4:对象缓存

对象缓存治的是「一次请求里同一份数据被反复查」。页面缓存是把整页 HTML 存下来,对象缓存是把数据库查询结果存到内存里,多个请求共用。

先判断值不值得上。 看单次请求的查询次数:

代码语言:bash
复制
wp eval 'global $wpdb; echo "queries: ", $wpdb->num_queries, "\n";'

同一个页面多跑几次。如果这个数一直是几十上百,说明每次都在重复查同样的东西,对象缓存有收益;如果只有十几次,先别折腾,把时间花在慢查询上更划算。

配好之后必须验证是否真的持久化。 很多人以为配好了,其实还是单请求内存缓存:

代码语言:bash
复制
# 第一个进程写入
wp eval 'wp_cache_set("probe", "1", "aumtest"); echo "set ok\n";'

# 第二个进程读取
wp eval 'var_dump(wp_cache_get("probe", "aumtest"));'

第二条输出 string(1) "1",说明跨请求共享生效了;输出 bool(false),说明还是单进程内存缓存。原理很简单:wp eval 每次都是新进程,进程内存里的东西活不过一次执行。这个验证方法不依赖任何插件。

还有一个容易忽略的点:页面缓存命中时根本不执行 PHP,对象缓存没机会起作用。所以页面缓存命中率越高,对象缓存能优化的那部分就越小。先看命中率,再决定要不要多维护一套 Redis。

Step 5:清缓存的顺序

内容更新之后,刷新的顺序是固定的:

  1. 清对象缓存(如果上了)
  2. 清页面缓存(源站)
  3. 刷 CDN
  4. 浏览器不用管,靠资源版本参数自动失效

反过来做会把旧内容推回 CDN:你先刷 CDN,用户请求打回源站,源站还是旧 HTML,CDN 又把这份旧的拉走存起来。看上去「刷了没用」,其实是顺序错了。

收尾

全部做完,再跑一次 Step 0 的 curl,和基线对比。如果 TTFB 没降,问题多半不在缓存层:可能是慢查询、外部 API 调用、或者 PHP-FPM 进程数不够。这时候继续往上叠缓存只会让排查更困难。

更多 WordPress 的实操记录在 AumCreate 的博客。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 四层各治哪种慢
  • Step 0:先测基线
  • Step 1:浏览器缓存
  • Step 2:CDN
  • Step 3:页面缓存
    • 3.1 http 上下文(放到 /etc/nginx/conf.d/ 下任意 .conf)
    • 3.2 server 上下文
    • 3.3 建目录、重载、验证
    • 3.4 清页面缓存
  • Step 4:对象缓存
  • Step 5:清缓存的顺序
  • 收尾
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档