前一段时间,为了提高 WordPress 的缓存命中率、减少页面回源带来的服务器压力,我逐步将 W3 Total Cache、EdgeOne 和 Cloudflare 的主要页面缓存生命周期统一调整到了 96 小时,也就是 4 天。
此前我已经在《从 CPU 告警到双域名预缓存:W3 Total Cache、EdgeOne 与 Cloudflare 96 小时缓存优化实战》中记录过这套缓存策略:
不过 4 天长缓存运行以后,也出现了一个比较实际的问题:
新文章已经发布,但 CDN 中的首页可能仍然是旧内容。
普通文章发布以后通常不会频繁变化,4 天缓存并没有什么问题。
但首页和 Sitemap 不一样。
每次发布新文章后:
- 首页文章列表会变化;
- Sitemap 索引可能变化;
post-sitemap.xml等子 Sitemap 也可能更新。
因此这一次,我没有重新降低整个网站的缓存时间,而是只针对这些高变化页面设置更短的 CDN 边缘缓存。
最终调整为:
| 页面 | CDN 边缘缓存时间 |
|---|---|
www 首页 | 2 小时 |
www 公开 Yoast Sitemap | 2 小时 |
en 首页 | 2 小时 |
en 公开 Yoast Sitemap | 2 小时 |
| 普通 HTML 页面 | 继续 4 天 |
| W3 Total Cache Page Cache | 继续 4 天 |
这样可以在保持大部分页面长期缓存的同时,把新文章发布后首页和 Sitemap 的最长旧缓存时间从 4 天缩短到约 2 小时。
一、为什么没有直接做“发布文章后自动清除 CDN”
理论上,更精确的方案是:
文章发布以后,由 WordPress 自动调用 EdgeOne 和 Cloudflare API,清除对应的首页与 Sitemap 缓存。
整个流程可以做成:
WordPress 发布文章 → 清理本地缓存 → 判断中文或英文 → 调用 CDN API → 精确 Purge 首页和 Sitemap。
这种方案能够让新文章几乎立即出现在 CDN 页面中。
但它也意味着需要继续维护:
- WordPress 发布 Hook;
- EdgeOne API;
- Cloudflare API;
- API Token;
- 中英文域名判断;
- Purge 失败处理;
- 重试机制。
而我目前真正需要解决的,并不是:
新文章发布后必须几秒钟就在首页出现。
而是:
不能因为 4 天 CDN 缓存,让首页长期保持旧内容。
如果最多接受约 2 小时的更新延迟,那么单独给首页和 Sitemap 设置较短 TTL,会简单很多。
因此这一次没有重新启用 WordPress 后台已经停用的 Cloudflare 插件,也没有增加自动 Purge 代码。
二、为什么统一选择 2 小时
最开始我考虑过把首页和 Sitemap 设置为 1 小时。
不过为了让 EdgeOne 和 Cloudflare 两边的配置保持一致,最后统一选择:
2 小时
这样以后再看缓存策略时也比较容易理解:
- 高变化入口:2 小时;
- 普通 HTML:4 天。
不需要记忆两套不同的时间。
更重要的是,这次只缩短少数几个高变化 URL,并不会明显影响整个网站的缓存命中率。
三、Yoast Sitemap 不只有 sitemap_index.xml
网站目前使用 Yoast SEO。
打开中文站:
https://www.shuijingwanwq.com/sitemap_index.xml
可以看到当前 Sitemap Index 中包含多个子 Sitemap。

其中包括类似:
/post-sitemap.xml
/post-sitemap2.xml
/page-sitemap.xml
/category-sitemap.xml
/post_tag-sitemap.xml
/post_tag-sitemap10.xml
/series-sitemap.xml
/series_group-sitemap.xml
所以只给:
/sitemap_index.xml
设置 2 小时还不够。
真正发布文章以后,最直接发生变化的往往反而是:
/post-sitemap.xml
因此这次需要同时覆盖 Sitemap Index 和各个公开子 Sitemap。
四、w3tc-preload-sitemap.xml 不纳入这次规则
网站还有一个特殊文件:
/w3tc-preload-sitemap.xml
这是此前为了 W3 Total Cache Cache Preload 单独生成的联合 Sitemap。
不过它的用途与搜索引擎公开访问的 Yoast Sitemap 不一样。
当前实现中,W3TC Preload 会通过自己的流程读取源站 Sitemap,因此这次需要解决的 CDN 内容更新问题,并不涉及这个文件。
所以:
/w3tc-preload-sitemap.xml不纳入“公开 Sitemap 2 小时缓存”范围。
这也意味着在 EdgeOne 规则中,需要明确把它排除。
五、EdgeOne:一条规则同时处理首页与 Sitemap
中文站:
www.shuijingwanwq.com
目前通过 EdgeOne 提供 CDN。
为了减少规则数量,我没有分别创建:
“首页缓存 2 小时”
和:
“Sitemap 缓存 2 小时”
而是创建了一条:
首页与 Sitemap 缓存 2 小时
最外层首先限定 Host:
www.shuijingwanwq.com
下面再创建两个同级 IF2。
第一个处理首页:
URL Path = /
第二个处理公开 Sitemap。

首页分支非常简单:
URL path 等于 /
操作:
- 节点缓存 TTL;
- 自定义时间;
- 2 小时;
- 强制缓存关闭。
Sitemap 分支使用正则:
^/(sitemap_index|[^/]+-sitemap[0-9]*)\.xml$
并增加:
URL Path 不等于 /w3tc-preload-sitemap.xml
这个正则能够覆盖:
/sitemap_index.xml/post-sitemap.xml/post-sitemap2.xml/page-sitemap.xml/category-sitemap.xml/post_tag-sitemap.xml/post_tag-sitemap10.xml/series-sitemap.xml/series_group-sitemap.xml
同时又不会让 w3tc-preload-sitemap.xml 最终进入 2 小时缓存。
保存以后,规则摘要如下。

六、EdgeOne 规则要放在原来的 4 天 HTML 规则之后
原来的:
HTML页面缓存(SEO安全)
仍然保留。
它负责普通 HTML 的长期缓存。
新增的:
首页与 Sitemap 缓存 2 小时
放在规则列表更靠后的位置。

因此普通文章不会因为这次调整全部降到 2 小时。
实际结果是:
普通 HTML → 继续 4 天
首页 → 2 小时
公开 Sitemap → 2 小时
这才是这次调整真正想达到的效果。
七、Cloudflare 当前已经有多条 Cache Rules
英文站:
en.shuijingwanwq.com
目前通过 Cloudflare。
开始修改以前,我先检查了现有 Cache Rules。

其中比较关键的是:
- HTML 页面缓存(SEO安全)
- WordPress 个性化 Cookie 绕过缓存
因此这一次也没有拆成多条规则,而是只新增:
首页与 Sitemap 缓存 2 小时
这样可以尽量减少规则数量,也方便以后维护。
八、Cloudflare 使用 Host + URI Path 匹配
Cloudflare 这边最终使用的表达式为:
(http.host eq "en.shuijingwanwq.com" and (
http.request.uri.path eq "/"
or http.request.uri.path eq "/sitemap_index.xml"
or http.request.uri.path wildcard "/*-sitemap*.xml"
))
这里分别处理:
首页:
/
Sitemap Index:
/sitemap_index.xml
其他子 Sitemap:
/*-sitemap*.xml
由于这条规则本身已经限定:
en.shuijingwanwq.com
而 w3tc-preload-sitemap.xml 位于中文 www 域名,因此 Cloudflare 这一侧不需要再专门排除它。
边缘 TTL 设置为:
忽略缓存控制标头,使用此 TTL
时间:
2 小时

浏览器 TTL 没有在这一步修改。
这次调整的重点只是:
Cloudflare 边缘节点缓存生命周期。
九、Cloudflare 的规则顺序同样很重要
新增规则以后,最终相关顺序变成:
- HTML 页面缓存(SEO安全)
- 首页与 Sitemap 缓存 2 小时
- WordPress 个性化 Cookie 绕过缓存

这个位置很重要。
普通访客访问首页时:
通用 HTML 规则先匹配,再由第 7 条把 Edge TTL 调整成 2 小时。
但如果请求带有登录或其他个性化 Cookie,最后仍然会命中第 8 条:
WordPress 个性化 Cookie 绕过缓存
因此不会因为增加了首页缓存规则,就把登录用户的个性化页面重新缓存起来。
十、新规则发布以后,先进行一次 URL Purge
仅仅修改 TTL,并不能保证节点中已经存在的旧缓存立即失效。
例如首页此前已经按照 4 天策略建立缓存,新规则发布以后,那份旧缓存仍然可能继续存在。
因此 EdgeOne 和 Cloudflare 两边配置完成后,我都做了一次自定义 URL 清除。
主要处理:
- 首页;
/sitemap_index.xml;/post-sitemap.xml。
没有执行全站 Purge。
这次清除的目的只是:
让已有的 4 天旧缓存失效,使新的 2 小时规则立即开始接管。
正常运行以后,并不需要每次发布文章都手工清理。
十一、第一次测试时发现代理会干扰 CDN 判断
最开始测试 EdgeOne 时,我连续访问:
- 首页;
sitemap_index.xml;post-sitemap.xml;- 一个普通文章页。
结果出现了:
- 请求超时;
- 多次 MISS;
- 普通文章也出现 MISS。
当时的 curl 输出还包含:
HTTP/1.1 200 Connection established
后来确认,本地请求经过了代理。
为了避免代理出口和 CDN 节点变化干扰测试,后面统一增加:
--noproxy '*'
例如:
curl -4 --noproxy '*' -sS \
--connect-timeout 10 \
--max-time 60 \
-o /dev/null \
-D - \
"https://www.shuijingwanwq.com/"
绕过代理以后,EdgeOne 首页很快得到:
第一次:
MISS
随后:
HIT
并且:
Age: 5
后面继续增长。
这说明首页已经成功进入 EdgeOne 节点缓存。
十二、EdgeOne Sitemap 与普通文章验证
接下来分别测试:
/sitemap_index.xml
/post-sitemap.xml
以及一个普通文章页。
结果:
sitemap_index.xml
第一次:
MISS
第二次:
MISS
第三次:
HIT
post-sitemap.xml
第一次:
MISS
随后:
HIT
HIT
这说明 Sitemap 确实能够正常进入 EdgeOne 缓存,同时也证明我们设置的匹配范围覆盖到了 /post-sitemap.xml。
而普通文章页则连续返回:
HIT
并且 Age:
221 → 226 → 231
说明新增规则没有破坏普通文章原来的长期缓存。
十三、Cloudflare 第一次验证同样成功
Cloudflare 清除缓存以后,对英文首页进行访问:
第一次:
CF-Cache-Status: MISS
随后:
HIT
Age: 3
再次:
HIT
Age: 6
说明首页重新进入了 Cloudflare 边缘缓存。
/post-sitemap.xml 也表现为:
MISS → HIT → HIT
因此:
/*-sitemap*.xml
确实能够匹配当前 Yoast 子 Sitemap。
测试普通英文文章时还出现了一组很有意思的数据:
LAX 节点:
HIT
Age: 28182
下一次请求到了 LAS:
MISS
随后又回到 LAX:
HIT
Age: 28190
这也提醒我:
CDN 的缓存不是整个网络共享一个统一 Age,而是分布在不同边缘节点中。
所以看到一次 MISS,不能直接判断缓存规则失效,还需要结合请求实际落到哪个 CDN 节点。
十四、MISS → HIT 还不能证明 TTL 真的是 2 小时
完成上述验证以后,还有一个问题:
我们只是证明缓存能够正常建立,但怎么知道 TTL 确实已经从 4 天变成了 2 小时?
例如:
MISS → HIT → HIT
无论 TTL 是:
- 2 小时;
- 4 小时;
- 4 天;
刚建立缓存时都有可能出现相同结果。
因此我没有立即结束测试,而是等了两个多小时以后再次检查。
十五、两个多小时后,EdgeOne 首页重新 MISS
EdgeOne 首页最初重新建立缓存大约是在 18:45 左右。
到了 21:12,再次测试。
第一次:
EO-Cache-Status: MISS
随后:
HIT
Age: 12
再次:
HIT
Age: 26
这表示此前已经存在的那份首页缓存,在两个多小时以后已经不再继续直接使用。
新的请求重新建立缓存以后,Age 又从很小的数值开始增长。
单凭一次 MISS,不能绝对排除节点变化、缓存淘汰等其他因素。
不过结合:
- EdgeOne 中明确配置为 2 小时;
- 配置后已经确认首页可以 HIT;
- 等待时间超过 2 小时;
- 再次访问变为 MISS;
- 随后立刻 HIT;
- Age 从十几秒重新开始;
实际行为已经与 2 小时节点缓存 TTL 完全吻合。
十六、Cloudflare 的 2 小时过期证据更加直接
Cloudflare 英文首页大约在 19:02 左右重新建立缓存。
到了 21:13 再次测试。
第一次返回:
CF-Cache-Status: EXPIRED
节点:
LAX
第二次:
CF-Cache-Status: HIT
Age: 4
仍然是:
LAX
第三次:
HIT
Age: 7
同样还是:
LAX
也就是说,在同一个 Cloudflare 节点上完整观察到了:
缓存存在 → TTL 到期 → EXPIRED → 重新获取 → HIT → Age 重新开始
因此 Cloudflare 这边可以比较明确地确认:
2 小时 Edge TTL 已经实际生效。
十七、为什么 Cloudflare 仍然返回 max-age=14400
Cloudflare 的响应中还有一个容易让人误解的地方。
即使 Edge TTL 已经设置为 2 小时,响应仍然显示:
cache-control: max-age=14400
14400 秒等于:
4 小时
但两个多小时以后,Cloudflare 已经出现:
CF-Cache-Status: EXPIRED
这并不矛盾。
因为这一次修改的是:
Cloudflare Edge TTL
而响应里的:
Cache-Control: max-age=14400
是客户端能够看到的缓存控制信息。
也就是说,目前可以同时存在:
Cloudflare Edge:2 小时
客户端 Cache-Control:4 小时
而且实际 EXPIRED 结果已经证明 Cloudflare 边缘节点没有继续按照 4 小时甚至 4 天缓存首页。
浏览器 TTL 是否也需要从 4 小时调整到 2 小时,是另外一个问题。
这次我暂时没有继续扩大调整范围。
十八、最终缓存结构
经过这次调整以后,目前主要策略可以概括为:
| 范围 | 缓存时间 |
|---|---|
| W3 Total Cache Page Cache | 4 天 |
| EdgeOne 普通 HTML | 4 天 |
| EdgeOne 首页 | 2 小时 |
| EdgeOne 公开 Yoast Sitemap | 2 小时 |
| Cloudflare 普通 HTML | 4 天 |
| Cloudflare 首页 | 2 小时 |
| Cloudflare 公开 Yoast Sitemap | 2 小时 |
w3tc-preload-sitemap.xml 不参与这次公开 Sitemap CDN TTL 调整。
Cloudflare WordPress 插件继续保持停用。
也没有增加 WordPress Hook 或 CDN API 自动 Purge。
十九、这次优化后的取舍
之前把缓存时间提升到 4 天,本身并没有错。
它解决的是:
普通页面反复回源、缓存生命周期过短、缓存命中率偏低的问题。
而这一次解决的是另一个问题:
首页和 Sitemap 属于高变化页面,不应该和普通文章完全使用相同的缓存生命周期。
因此最终并不是在“2 小时”和“4 天”之间二选一,而是按页面性质区分:
而是按页面性质区分:
稳定页面使用 4 天长缓存,高变化入口使用 2 小时短缓存。
这样发布新文章以后,即使完全不做主动 Purge,CDN 边缘层面的旧首页和 Sitemap 最多也只需要等待约 2 小时。
与此同时,大量普通文章仍然可以继续享受 4 天缓存。
相比为 EdgeOne 和 Cloudflare 分别实现文章发布后的自动清理,这套方案简单很多,后续维护成本也低。
而从实际等待两个多小时后的测试结果来看:
- EdgeOne 出现
MISS → HIT,Age 重新开始; - Cloudflare 明确出现
EXPIRED → HIT,Age 从 4 秒重新开始。
因此目前我准备继续保留这套配置。
以后如果实际需求变成:
文章发布以后,首页必须立即出现新内容。
再进一步引入 CDN API 精确 Purge。
但对于目前的网站来说,首页和 Sitemap 2 小时、普通页面 4 天,已经是一个更适合当前访问规模和维护成本的折中方案。
Linux 服务器运维、部署与线上故障排查
如果你的网站或后端服务部署在 Linux 服务器上,遇到访问异常、Nginx 配置问题、MySQL / Redis 异常、Docker 服务不可用、磁盘占满、CPU / 内存过高等问题,可以联系我做一次远程排查。
适合以下场景:
✅ 网站打不开或访问不稳定
✅ Nginx / PHP-FPM 配置异常
✅ MySQL / Redis 性能或连接问题
✅ Docker 服务部署与维护
✅ 服务器迁移与环境配置
✅ CPU / 内存 / 磁盘异常排查
服务内容:
✅ Linux 环境检查
✅ 网站部署与迁移
✅ Nginx / PHP-FPM / MySQL / Redis 排查
✅ Docker 配置与维护
✅ 服务器性能分析
✅ 长期远程运维支持
如需咨询,请联系我,并注明:Linux 运维咨询。
联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com


发表回复