Contents
1 背景介绍
最初之所以会萌生要搞一套 WordPress 多活方案的想法,最根本的导火索其实很简单:那次家里毫无征兆地被电信断网整整 3 天(详见文章:家庭数据中心系列 从这次家里被断网谈当下个人博客建站的可选方式)。因为当时我博客的WordPress只有家庭数据中心这一个节点,结果直接导致博客直接歇菜,无法访问了。虽然当时紧急把数据迁移到了腾讯云的轻量服务器上,也在大约 2 个小时后恢复了访问,但那段时间的郁闷至今仍然印象深刻。也就是在那一刻,我暗下决心:必须要搞一套真正意义上的 WordPress 双活架构(当时只想到双活),让家里的博客哪怕出问题,也能第一时间无缝切换到备用节点,不再出现这种“好好的博客说没就没”的尴尬局面。
只不过,那个时候我搭建和运维博客还不到一年,很多知识还处于碎片化探索阶段,体系远远不够完整,结果折腾到最后,也只好先退而求其次,先搞了一个半吊子的灾备方案,以尽量预防类似事故再次发生(详见文章:家庭数据中心系列 活用cloudflare tunnel实现WordPress主站点故障时灾备站点自动接管)。
这个灾备方案在当时看起来确实算是解了燃眉之急,但从现在回头看,却有一个非常明显、几乎可以说是致命的缺陷:腾讯云节点到底该如何精准、可靠地判断家里的 macmini(主站)是否真的发生了异常?那时候我能想到的方案其实都挺土,要么是在腾讯云上定时执行脚本,直接访问 https://blog.tangwudi.com 的某个不经过缓存的探活页面,以此来判断家里的服务是否正常;要么就是通过 tailscale 的内网 IP 直接访问 macmini 上的 WordPress 页面,看能否正常加载。
不过,这两种方法其实都各有明显短板:
- 前者很容易受到包括线路在内的各种外部因素的影响,探测结果未必能准确反映站点的真实可用性;
- 而后者虽然可以更直观地探测到 macmini 上 WordPress 的运行状态,但却完全依赖两端的 tailscale。如果任何一端的 tailscale 出现异常,都有可能导致腾讯云节点判断失误,进而和主节点同时处于UP状态。
再加上这种灾备切换也只是“被动接管”,只能实现1活1灾备,还做不到真正的多活同步(当时根本不知道如何解决WordPress的数据库同步问题,也对Cloudflare Tunnel多connector的工作原理完全不了解),这就促使我后来不停摸索适用个人博客的WordPress双活乃至可以进一步可以动态扩展的多活架构,而在VPS从腾讯云搬家到Racknerd之后才彻底改造完成(参见文章:家庭数据中心系列 博客架构的第二次重构:VPS搬家引发的服务迁移与双活容灾实践),而后续还进行了优化(参见文章:家庭数据中心系列 博客架构的第三次优化:WordPress双活节点调整与数据库导入注意事项)。
注:本文以描述架构方案为核心,技术实现与配置步骤请参考文中给出的实操文章链接,避免赘述以保持结构清晰。
2 WordPress多活解决方案面临的技术难题
但是嘛,真要落地一套可以动态扩展、真正意义上的 WordPress 多活架构,可远远不是多准备几台服务器互相备份、定时同步一下数据库就能搞定的事。
它所要面临的技术难题,可以从三个层面来总结:

1️、流量调度:就近访问与容灾切换
首先就是用户的流量该怎么智能地进入离他最近、且健康的节点。这涉及最常见的 DNS 轮询、GeoDNS 或 F5 GTM 那类全局流量调度方案,还得解决健康检查的问题:比如怎么避免因为探测延迟,把用户流量分配到其实已经挂掉的节点?又该如何做到在节点出现故障后快速切换,同时在节点恢复后能自动恢复进流量池?这些听上去再正常不过的需求,背后其实都需要非常扎实的健康监测和流量切换机制做支撑。
2️、数据同步:多节点一致性与文件资源
然后就是更麻烦的多节点数据一致性问题。WordPress 不只是数据库层面的文章、评论数据同步,还要考虑用户上传的多媒体文件究竟是同步到各节点本地,还是干脆挂上对象存储或分布式文件系统?
哪怕数据库用主从、双主,或者更先进的 Galera Cluster,依然要解决写入冲突、数据延迟、分裂脑的问题;就算这些都做了,Redis、Memcached 这类缓存还得想办法跨地域同步,否则不同节点还是可能读到不一致的页面状态。
3️、写入冲突与读写分离
再往下就是写入问题。在多活场景下,如果用户在不同节点发起写入(比如发表评论、注册、上传文件),就很容易引发冲突或版本错乱。传统架构里往往会用读写分离来避免这种情况:所有写请求都固定进主节点,其他节点只负责读,通过延迟复制或最终一致保证不至于太乱。
看似理所当然,其实每一步都需要很多机制相配合。这些东西在架构图上画起来不过几条箭头,听上去好像再正常不过,但真要在底层一一实现,几乎每一个环节都需要付出成倍的代价:不管是跨区域多活的文件同步,还是分布式数据库的一致性协议,再或者是全局 DNS 的探活与动态路由。也正因为如此,大多数个人博客站长最多选择单节点 + CDN 的方式图省心,很少有人去折腾真正意义上的多活架构 —— 因为实在太容易把自己绕进去。
所幸,我这里只是一个简单的个人博客(还关闭了注册~,所以根本不用考虑用户数据写入带来的麻烦),绝大多数访问请求都是读,写请求绝大部分是”可控写”(定期发布或者修改文章),”不可控写”少得可怜(就是偶尔有人评论)。所以在这三大看似严肃无比的多活课题上,我其实都可以大胆地做一些妥协:
1、在流量调度层面
对于个人博客来说,其实完全不需要追求企业级那种毫秒级多维度健康检测、自动剔除失效节点、动态负载权重调节。只要能把流量合理分配到多个可用节点,就已经大幅降低了单点故障的风险。真要碰到节点突然挂掉,偶尔有请求被分到失效节点返回错误,也完全可以接受。
2、在数据同步与一致性层面
我的站点以文章阅读为主,基本都是静态内容,哪怕不同节点之间的数据同步存在一些延迟,也不会影响大多数用户的正常访问体验。评论等动态数据在这种场景下偶尔出现一段时间的不同步,也不会带来实质性的问题(甚至可能都没人发现~)。至于媒体文件,只要事先在各节点之间保持一致,就不需要用到那些复杂的分布式文件或对象存储方案。
3、在写入冲突与读写分离层面
如果换作是电商、社交网络那种场景,写入冲突和数据一致性几乎都必须被严肃对待,通常要依赖单点写入或分布式协调一致的方案来保证正确性。但我的博客写请求极少,几乎不存在高并发写入的压力。哪怕偶尔在后台操作,或者有访客发评论,也极少触发真正的冲突风险,更不至于影响到整体的数据完整性。
所以说,这些看似“降低多活技术标准”的妥协性做法,其实完全是基于我个人博客的实际使用场景所做出的理性选择:哪怕在专业架构里需要非常严肃对待的流量调度、数据一致性、写入冲突问题,在我这里都可以接受一定程度的弱化和延迟。只要能避免因为家里被断网就让博客直接全线瘫痪,对我来说,就足够了。
更何况,通过选用合适的技术组合,很多看似缺失的部分其实也能在一定程度上被弥补。
3 基于 Cloudflare Tunnel 的多活流量调度
相对于传统商业环境下自建多活数据中心的流量调度方式(比如以 F5 GTM 为代表的智能 DNS 解析、全局负载均衡体系),个人博客要想实现多活节点的流量分发,显然就不适合采用这种思路了。
不仅因为这些方案成本高昂、配置复杂,更因为它们往往依赖自有 BGP Anycast、区域健康探测、或需要多家运营商合作来完成全球路由优化,根本不是个人站长能触及的范畴。
所幸的是,大善人 Cloudflare 提供的 Tunnel(以前叫 Argo Tunnel)天然就带有多节点的入口分发与就近调度能力。它能在全球范围的 Cloudflare 边缘网络上帮我自动探测可用性,把流量引到离访客最近、响应最快的那台节点。这样不仅大幅降低了我自己在 DNS、健康检查、线路调优上的投入难度,也顺带解决了失效节点剔除的问题。
需要注意的是,Cloudflare Tunnel 虽然免费就提供了多节点入口分发和就近调度的能力,但严格来说,这其实只是一种面向可用性与故障转移的best effort(尽力而为)机制,官方描述如下:

官方文档原文地址如下:Tunnel availability and failover。
它的多活实现只是允许你在多台服务器上同时运行同一个 tunnel 的连接器(connector),这样 Cloudflare 的边缘网络就可以根据用户的地理位置和网络状况,优先把请求转发到最合适的节点,如果某个节点失效或探测不到,也会自动切换到其他可用节点(更多关于物理位置、tunnel和connector之间关系的说明参见文章:家庭数据中心系列 cloudflare教程(九) Zero Trust常用功能介绍及多场景使用教程)。
不过需要明确的是,这并不是传统意义上的智能流量调度:没有细粒度的流量比例控制,也没有严格的轮询或哈希分配算法。Cloudflare 的调度更多依赖于边缘节点与 connector 之间的健康探测与网络距离的动态估算,大多数时候都能做到比较合理的就近访问,但也只是“尽力而为”。比如明明从网络延迟上看,芝加哥节点比我的家庭数据中心快好几倍,理论上用户的请求应该都优先进入芝加哥节点,但实际情况是,偶尔还是会有少量请求被分配回家里。对于严格要求毫秒级优化的大型商业系统来说,这种不确定性是无法接受的,但在我的个人博客场景下完全可以容忍。
所以总体来说,这种模式更适合作为高可用场景下的入口保障,用于避免单点故障,而不是为了精准的流量负载均衡。对我而言,只要能在家里被拔网线或者某台服务器挂掉或者停电时,依然有其他节点接管流量,博客就能继续对外可用,这就已经让我满意了。
由于Cloudflare Tunnel的单个Tunnel最多支持25个活动副本(官方文档地址:https://developers.cloudflare.com/cloudflare-one/account-limits/):

所以,理论上来说,这种多活架构最多支持扩容到25个节点,还是有上限的,不过,对个人博客而言已经够了吧~。
4 附加探讨:Cloudflare Tunnel 与「全封闭」安全架构
在前面几章主要讨论了如何利用 Cloudflare Tunnel 来实现多活架构的流量调度。但其实,Cloudflare Tunnel 给我带来的收益,并不止是流量分发的智能化,还在于它从根本上改变了传统基于「公网 IP + 端口」的安全边界思路。
过去,我们习惯于用防火墙规则来勉强维护服务器的安全:比如只开放 80/443 用于 HTTP(S),只对固定 IP 段开放 22 来做 SSH,剩下的全部 Drop。然而只要在互联网上暴露了这些众所周知端口,就不可避免地会被无数扫描器盯上——masscan、zmap、nmap、自动化弱口令爆破、各种 web 漏洞扫描脚本,几乎每分钟都在撞你的门。即便你在防火墙和 Fail2Ban 上做得再细,日志还是会像堆垃圾一样不断增长,充斥着连接探测、可疑请求、甚至 DDOS flood。最可怕的是,这种“被看到”,本身就暴露了你的存在:攻击者只要探测到有22、 443端口存活,就能把你列进下一轮更精准的攻击池。
而 Cloudflare Tunnel 则几乎从物理上消除了这个问题。它的核心机制是从 VPS 主动发起到 Cloudflare 边缘节点的加密持久连接,根本不需要在公网层面对外开放任何端口。这意味着可以在 VPS 上直接把所有入向流量(TCP、UDP、ICMP)统统 Drop,让你的机器在互联网上彻底消失。所有针对你 IP 的端口扫描、漏洞探测、自动化攻击都会在第一步就失败,因为对它们来说,这台机器压根就不存在(还有一个前提是也不要有任何域名解析指向VPS的公网IP,否则还是还是会泄露,看看那些渗透测试的第一步就知道了)。
这样一来,应用入口都是使用Tunnel里配置的公共主机名进行发布,所有安全压力自然全部转移到了 Cloudflare 上——只要在 Dashboard 配置好 WAF、速率限制、Bot 管理、DDoS 防护,就已经足以抵御绝大多数威胁(这时如何真正用好Cloudflare就是关键了,不熟悉的朋友可以参考:cloudflare学习地图),而你的 VPS 则成为了一个真正意义上的“黑洞节点”:没有入口,自然也就无从攻破:

也正是基于这样的安全策略,我在后面涉及文件同步等需求时,彻底放弃了“通过 VPS 公网 IP + 端口直连”来发布 HTTP 服务的老思路,不给互联网上的任何爬虫或扫描器留下探测网站服务的机会。
注1:理想很丰满,现实却很骨感。理论上,这样的全封闭策略可以做到连 SSH 都通过 Tailscale 的私有网络来运维(因为 Tailscale 同样是基于外向连接,与这种封闭模型非常契合,我之前在腾讯云轻量服务器上就是这么用的)。但奈何跨境 Tailscale 流量在我的场景下被严重劣化,几乎不可用,只好退而求其次,开放了一个SSH服务的高端口(打死不能直接用22端口),仅允许SSH公钥认证、禁用密码登录,这样尽可能把暴露面降到最低,同时又能使用scp、rsync等能基于SSH连接传送文件的方式。
注2:默认情况下,Cloudflare Tunnel 使用基于 QUIC 的外向连接(UDP 443 + TLS),这在流量特征上非常明显,在国内网络环境下容易被识别和干预。为了更稳妥,建议将其切换为 HTTP/2 模式,降低被针对的风险,具体操作参见文章:家庭数据中心系列 从 QUIC 到 HTTP2:打造更隐秘与稳定的Cloudflare Tunnel方案。
5 基于 rsync 的轻量数据同步与一致性实践(多活场景)
5.1 数据同步方案的选择
要使用前一章介绍的 Cloudflare Tunnel 提供的多节点入口分发与就近调度能力来实现多活架构,一个理所当然的前提就是:各个节点提供的内容必须完全一致。否则就算流量调度再智能,用户访问到不同节点看到的数据如果不一致,就失去了多活的意义。
在典型的商业场景里,要做到多节点间的数据一致,通常会采用以下几类方案:
- 主从复制(Master-Slave Replication):比如 MySQL、PostgreSQL 最常见的主从结构,单点写入,多点读取,靠 binlog 或 WAL 日志在异地节点实时回放。
- 双向复制或多主(Master-Master):两地都可以写入,需要额外引入冲突检测与解决,比如 Galera Cluster、MySQL Group Replication。
- 分布式数据库(NewSQL/NoSQL):如 CockroachDB、TiDB、Cassandra,通过 Paxos/Raft 等分布式协议确保跨节点数据一致性,代价是更复杂的维护和更高的网络质量要求。
- 文件级分布式存储:比如 CephFS、GlusterFS,通过多副本和一致性协议在多个节点之间分散文件和元数据。
这些在大公司、跨国互联网项目里很常见,能保证在不同地理位置的多个节点读写都保持非常严格的一致性,但也有非常显著的前提条件:需要可靠的网络质量和极低延迟,否则就会导致延迟剧增、锁超时、甚至脑裂等严重问题。
可惜,回到我这个场景来看——我的家庭数据中心在国内,另一个节点在Racknerd芝加哥的VPS,中间全靠跨境线路,网络延迟高、抖动大、还经常丢包。用上面提到的这些企业级分布式同步方案根本就不现实,光是 TCP 连接可能就动不动被重置,更别提依赖稳定心跳和严格一致的数据库集群。
所以最终我只能选择一种更轻量化、宽松一致性的思路:在家庭数据中心和芝加哥节点都部署一套独立的 WordPress,然后通过导出家庭数据中心节点的WordPress的库,之后同步库文件到芝加哥节点并导入的方式,保持绝大部分时间内容一致(其实只要我没有发布新文章、修改文章以及没有新评论的时候,就是一致的)。这样就算跨境线路再差,也不会阻塞本地节点的正常读写操作。
注:目前因为评论较少(有时一周也未必有一个),所以暂时我还是采用的手动触发的方式来导出WordPress的库文件,如果评论真的多了起来,就需要升级到定期导出、同步的方式了。
5.2 同步工具为什么选择rsync?
至于同步数据库文件的具体方式,其实我也折腾过不少方案。
一开始,我尝试在家庭数据中心和芝加哥VPS之间,借助 Syncthing(具体配置细节可参考另一篇文章:docker系列 使用docker基于syncthing实现多点文件夹同步之详细教程)配合 Tailscale的私有IP来实现点对点的自动同步。这种方案在局域网或者国内范围都还运行得挺好,几乎零延迟(之前和腾讯云服务器之间同步数据库文件就是这样用的)。然而,一旦跨境就惨不忍睹:Tailscale 的流量在跨国链路上被严重劣化,几乎连SSH或者访问web页面都很慢,更别说用来传输几十上百兆的数据库文件了。
而我又因为之前已经做了“全封闭”的安全架构设计,不太愿意在公网再暴露一个用于 Syncthing 的同步端口,所以只能遗憾地放弃了这一思路。
之后因为已经为运维在芝加哥的VPS上开放了一个高位 SSH 端口,于是转向了最原始也最省心的方案:直接用 SCP 来传输数据库文件。正常情况下,这种方式其实足够简洁好用,配合 SSH 公钥认证几乎零配置(SSH公钥认证的具体配置可以参考文章:debian系列 配置ssh公钥登录)。然而一旦遇到跨境线路抽风,SCP 的全量单次传输特性就成了致命短板,经常卡在某个进度百分比直接超时失败,得从头再来,哪怕只差几 MB 也要重传。
最终,还是回归到更专业、也更适合不稳定链路环境的 rsync:它不仅天然支持断点续传,还能通过 –partial、–append-verify 等参数优化续传行为,几乎能最大程度地把传输成本降到最低。再加上配合简单的 shell 循环脚本来做失败自动重试,即便线路质量偶有波动,也能悄无声息地把数据一点点搬过去,最终成为了我多活数据库同步的最佳选择(具体细节可以参考文章:家庭数据中心系列 用 rsync 优雅解决跨国 VPS 文件同步的顽疾)。
6 多活架构下的主写节点与写入冲突避免
在上一章中,既然是从家庭数据中心节点的WordPress导出库文件并同步到芝加哥节点的WordPress,就已经确定家庭数据中心节点的WordPress必须作为主写节点,这也是最适合我平时管理的方式。毕竟,我平时都是直接通过内网IP来管理macmini上的WordPress进行文章的发布和修改,乃至是批准和回复评论。
为了把这个主写节点的模式说得更清楚,插一句运维层面的细节。
芝加哥节点只开放了一个 SSH 的高位端口,并且只允许公钥认证,所以根本没法像家里那样直接用公网 IP 登录后台管理(当然也可以用 SSH 端口转发,但我懒得每次都先开一条隧道)。
通过 tailscale 虽然也能访问芝加哥节点的 WordPress,可惜跨境速度太慢,只能当应急手段,不适合日常管理。
所以,让家庭数据中心的 WordPress 作为唯一的主写节点,然后把修改后的数据推送到其他节点,是最省事也最顺手的方式。最关键的是,哪怕以后再增加更多节点,也只是脚本里多几条命令的事,脚本依旧只需执行一次就能同步完,不会显著增加运维负担。
如果仅仅是这些”写”动作,那根本就没有写入冲突这回事了,因为这些都是可控写入。最关键还有一件虽然频率低但是却不可控的”写”动作:评论。如果仅靠Cloudflare Tunnel自带的多活流量调度能力,结果就是大概率写到芝加哥节点的WordPress,小概率写到家庭数据中心节点的WordPress,这对于将家庭数据中心节点当做主写节点的我来说是不可接受的,那么如何确保评论能写入家庭数据中心节点呢?
早期最直接的做法是将所有用户评论请求强制引导至主节点数据库写入,确保数据源的一致性和集中化管理。而为了实现这一目标,常见的思路包括:
- 跨域写入方案:在主节点的 WordPress 中配置 CORS 头,允许其他只读节点通过 JavaScript 的 AJAX 请求,将评论直接提交到主节点(如 comment.tangwudi.com)。这种方式实现相对简单,但涉及浏览器跨域限制,需妥善配置 Access-Control-Allow-Origin 等响应头,并处理好 Cookie 的作用域问题。
-
反向代理回写方案:在每个只读节点的 Web Server 中,将用户对 admin-ajax.php 或 wp-comments-post.php 的 POST 请求反代至主节点。该方法对用户透明,无需修改前端代码,也不存在跨域问题,但在实践中需关注会话保持、缓存穿透等细节,否则容易出现认证丢失或 CSRF 校验失败等问题。
这两种方式我都尝试过,都太折腾,而且极容易踩坑,把我折腾得够呛。
最终,我选择了一个既轻量、又最符合我分布式网络现状的方案——借助 Cloudflare Worker 作为评论写入的智能中转层。
通过 Worker 部署在 Cloudflare 全球边缘节点上,能够在离访客最近的地方就拦截到评论提交请求,并由 Worker 再主动转发到我的后端节点进行实际写入。
这样做有几个显而易见的优势:
- 不需要修改任何前端代码(不像 CORS 那样需要重新写 Ajax 提交逻辑),
- 天然规避浏览器的跨域安全限制,
- 同时还能在边缘做一层额外的防护、审计和限流。
在基于 Worker 的写入方案中,还可以进一步分成两种不同的策略:
1、只写入主节点(家庭数据中心)
这是一种最“经典”的单点写入做法,能够保证所有评论数据都集中在家庭节点的数据库中,完全避免多点写入可能引发的冲突或数据分叉。但缺点同样明显:其一,如果家庭节点短暂失联,评论提交就会直接失败,用户体验会非常差;其二,在尚未同步到其他节点之前,如果访客被 Cloudflare 分配到芝加哥节点,就无法立即看到刚刚提交的评论。
2、同时写入所有节点
也就是让 Worker 在接收到评论请求后,直接将同一条评论并发 POST 到家庭节点和芝加哥节点,实现多点数据库同时写入。这样无论后续访客被调度到哪个节点,都能第一时间看到自己的评论,大幅降低因同步周期导致的可见性差异。
不过需要注意,这种多点写入的“土办法”放弃了单一数据源的严格一致性,在极少数情况下(比如配置缓存后,不同节点生成的评论自增 ID 不同,导致访客看到的缓存 ID 与实际回复节点的 ID 不匹配)可能引发二级评论失败。但对于我个人博客这种极低并发场景,这点偶发的不一致完全可以接受,换来的却是更好的即时可见性(而且回复评论的时间我也是可控的,除非是几位访客自己在评论区聊天~)。哪怕偶尔出现重复或回复异常,也远比家里断网就让评论功能直接挂掉要好得多。
在这样的权衡下,我最终选择了第二种方案:让 Cloudflare Worker 同时将评论写入所有节点。对于几乎没有人在评论区“实时对话”的个人博客而言,这反而是一种最简单、最直接的高可用解法(这部分内容具体技术细节参见文章:家庭数据中心系列 用 Cloudflare Worker 解决 WordPress 多活架构中的评论同步难题)。
7 Cloudflare APO:让多活架构真正脱胎换骨
7.1 现有多活架构的局限
说到这里,你可能会发现一个挺有意思的问题:虽然前面那一整套基于 Cloudflare Tunnel 的多活流量调度、再加上 rsync 同步、主写节点控制写入,已经实现了真正意义上的多节点可用。但它的本质,其实并没有跳脱出传统 WordPress 的运行范式——每次用户访问都还是要回到某个节点上执行 PHP + MySQL,动态生成页面再返回给用户。
所以它仍然依赖:
- 各节点自身的 PHP / Nginx / MySQL 性能。
- 依赖 Redis 或 Memcached 来做对象缓存。
- 依赖各种 WP Rocket、Autoptimize、Query Monitor 之类的经典本地优化插件。
- 甚至依赖节点不出故障,不突然硬盘损坏、数据库崩掉、php-fpm 爆内存……
最关键的是,这种架构下并没有一个真正意义上的“缓冲带”:
- 一旦某个节点出现 PHP 报错、数据库宕机或者哪怕只是网络短暂波动,Cloudflare Tunnel 就还是会把用户请求分发给这个节点,用户就会直接撞上 502、504 或 500 错误。
- 芝加哥节点有点小问题,美东的用户就最先撞上;家庭数据中心被拔网线,国内用户就最先感受到。
在这样的模式下,多活架构虽说提高了可用性,减少了单点故障的风险,但用户体验依旧容易在节点层面被直接暴露,没有任何缓冲。
7.2 Cloudflare APO
7.2.1 什么是 Cloudflare APO?
说到提升 WordPress 的性能,绝大多数人首先想到的都是安装各种缓存插件,比如 W3 Total Cache、WP Super Cache 或者用 Redis/Memcached 做对象缓存。这些方案确实能让单台服务器抗更多用户请求,但它们依然是运行在节点本地,仍需依赖节点的 CPU、内存、IO 性能来处理请求。
Cloudflare APO则从根本上改变了这个思路,将WordPress的本地访问模式变成了云端缓存访问模式。那么,Cloudflare APO到底是什么?
Cloudflare APO(Automatic Platform Optimization),是 Cloudflare 针对 WordPress(以及后续逐步支持的多种平台)推出的一个“智能边缘全站缓存”方案。它的核心理念非常简单:与其每次都让用户访问你的服务器,由 PHP+MySQL 去动态生成 HTML,再返回用户,不如把完整的页面(HTML)直接缓存到离用户最近的 Cloudflare 节点上。
这样做的结果是:
- 绝大多数用户请求直接在 Cloudflare 的全球 300+ 数据中心被命中,完全不会触发回源。
- 只有首次访问或缓存失效后,Cloudflare 才会向你的服务器回源拉取页面。
- 用户拿到的是“在边缘就已经生成好的完整页面”,不仅快,而且你的服务器压力会骤降。
7.2.2 Cloudflare APO和传统CDN的区别
很多人乍一听可能会说:这和普通的 CDN 有啥区别?不是早就可以把静态资源缓存到全球各地了吗?
其实区别很大:
- 传统 CDN 通常只会缓存那些设置了合适 Cache-Control 或 Expires 的文件,而大多数网站默认只在 JS、CSS、图片上加这些头,HTML 页面往往不会被缓存。要让 CDN 缓存 HTML,通常还得在服务器或 CDN 里额外配置规则。而像 WordPress 这样的动态站点默认就没有针对 HTML 页面生成可缓存的响应头,想让它和传统 CDN 配合好,需要手动装一堆缓存插件、写 purge 钩子脚本,折腾非常多。
- Cloudflare APO 则是专门为 WordPress 量身定制的。它通过 WP 的 REST API 或 XML-RPC 主动与你的 WordPress 通信,实时感知是否发布了新文章、批准了评论、修改了菜单……只要有变动,就能立即触发 Cloudflare 在全球所有边缘节点的缓存失效,自动刷新 HTML 页面缓存,真正做到「动态内容的全站边缘缓存」。
换句话说,APO 提供了一个 面向 WordPress 的动态全站缓存解决方案,让你的博客在全球范围几乎都能直接在边缘交付完整页面,而不必担心更新不同步或需要复杂的自定义 purge。
再说明白一点,在启用了 APO 之后,Cloudflare 会为你:在全站范围内缓存完整的 HTML 页面,而不仅仅是图片和脚本;监测你的站点是否发布/更新文章、收到评论、或有菜单结构变更;一旦检测到站点数据更新,就通过后台主动调用失效 API,通知 Cloudflare 全网边缘节点清理相关页面的缓存。
这就大大优于一般的 Nginx FastCGI Cache 或者通用 CDN,因为:你不用再去手动写什么 purge 脚本;不用在 WordPress 中安装一堆为了配合缓存而存在的插件(例如 W3TC 的页面缓存 + 缓存失效钩子);对于评论、新文章,APO 都能几乎实时地更新所有边缘节点。所以,5 美金/月的 APO,可以说是我认为对 WordPress 用户最超值、最无脑的投资之一。
当然,也可以用 Cloudflare Worker 来手动实现一个免费的”乞丐版 APO”(具体可以参考我之前的文章:家庭数据中心系列 cloudflare教程(七) CF worker功能介绍及基于worker实现”乞丐版APO for WordPress”功能加速网站访问的实操、验证及相关技术原理研究),但这种方案的内容动态缓存和版本管理依赖于一个叫“Cloudflare Page Cache”的插件,这个插件已经很多年没更新了,Github上Cloudflare官方页面都没提供了,也不知道现在还能不能正常工作。另一方面来说, 这个方案依赖于Cloudflare的KV,而免费额度送的 KV 空间也总是让我有点不放心——用量还没多少,就容易收到 Cloudflare 发来的「已使用 50%」的提醒邮件,看着就蛋痛。
所以说,这种免费的 DIY 折腾法其实真没啥必要:WordPress 都跑起来了,干脆花个 5 美金让 Cloudflare 官方帮你把缓存托管、主动 purge、全球加速全都搞定,省心省力多了。而且如果你已经订了 Cloudflare Pro,APO 直接就送,等于这 5 美金都不用掏了,对 WordPress 用户来说,简直超值。
注:Free用户与Pro用户提供的功能差异对比可以参考这篇文章:家庭数据中心系列 Cloudflare Pro 深度体验:从 Free 到 Pro,到底值不值得升级?。
不过,APO在使用中也可能因为一些意外的因素(比如cookie)而失效,我之前就遇到过一次,排查就花了我不少时间,感兴趣的朋友可以参考文章:家庭数据中心系列 Cloudflare APO 缓存失效解析:Cf-Cache-Status BYPASS 的原因与解决方案。
其实,很多博主并不是不知道 WordPress 站点直接用 VPS 公网 IP 来发布既不安全、也缺乏高可用保障,但最终还是这么做了。为什么?因为一旦涉及到 CDN 缓存,复杂度立刻翻了十倍,还得自己不断踩坑、调试。相比之下,直接裸跑虽然隐患不小,但胜在简单、直接。
这也恰恰是 WordPress(乃至绝大多数动态 CMS)长期被人吐槽性能差、安全脆弱的原因:
- 高并发下 PHP + MySQL 抗不住,容易崩。
- VPS 一旦被打(比如 WordPress 老版本常见的 XML-RPC 放大攻击,或者 WP-JSON 接口暴力枚举),就容易 502。
- 没有缓存缓冲层,任何小故障用户都第一时间感知到。
现实来看,小网站、流量低的网站(个人博客、作品集)通常就直接公网 + Nginx + PHP-FPM,懒得搞那么复杂。而一旦追求全球加速、抗高并发、多活,就会陷入复杂的缓存管理深坑,APO 其实就是把这些常见的坑,用“WordPress 感知 + 自动 purge + 全面 HTML 缓存”一次性解决了。也正因如此,只有亲手维护过 WordPress CDN 缓存的人,才最能体会 APO 能省下多少运维心力。
7.2.3 为多活架构提供了真正的「缓冲带」
对像我这样已经有WordPress多活架构的场景来说,APO 让常规请求在多活架构下的”多点回源”,变成了”以Cloudflare边缘网络为主、WordPress节点回源为辅”的响应模式:
- 在没有 APO 的多活架构里,用户访问会被 Cloudflare Tunnel分发到不同的WordPress节点,节点直接承担 PHP + MySQL 生成页面的任务。
- 而有了 APO,用户压根不会访问到具体节点,99% 的请求都被 Cloudflare 在边缘就处理完,节点只在缓存失效后才被拉去生成页面。
这不仅显著提升了性能,更极大增强了可用性——哪怕某个节点出现短暂的网络波动、PHP 报错甚至数据库瞬时不可用,用户都几乎不会感知到,因为 Cloudflare 已经把完整的 HTML 页面缓存到了全球边缘网络中,真正让多活架构不仅仅是“多节点可用”,更是在 用户体验层面多了一层强力的隔离保护带。
换句话说,哪怕你的某个节点在背后已经冒烟起火,访客依然能从最近的 Cloudflare 节点直接拿到完整页面,丝毫不觉察后端的异常。这就是多活架构下 APO 所提供的真正价值:哪怕有节点故障,也还有其他节点可以承担回源,继续为全球的边缘缓存提供新鲜血液。
当然,如果你只是单节点架构,情况就不一样了——一旦源站完全失效,Cloudflare 虽然还能短时间继续用旧缓存服务用户,但很快就会显示“源站不可用”的提示,缓存也无法被进一步更新,等于是失去了后继的保障。
注1:这样的架构也会带来一些新的麻烦。例如前面提到过的评论 ID 不一致问题:由于回源已经变成了多个独立的 WordPress 节点,访客在不同时间或不同地点提交评论,可能写入的是不同节点的数据库,导致生成的自增 ID 不同。这种问题在单节点架构下根本不会存在,而在现在这种分布式回源的多活环境下却是常态。它并不是 APO 造成的,而是 APO 在加速访问、屏蔽节点故障的同时,让这种多节点的差异更容易被暴露出来,需要通过后端的数据同步来加以平衡。
注2:在启用了 APO 的多活架构下,其实节点数量并不需要像传统那样越多越好。因为绝大多数用户请求,早就在 Cloudflare 的边缘网络就被直接命中返回了,服务器真正承担的只是缓存未命中时的回源职责。所以多活架构的意义,也从过去为了分摊压力、提高并发能力,转变成了更纯粹的可用性保障——只要在不同地理位置各有一个节点,比如像我现在一样:家里一个、海外一个,就足以应对绝大多数风险,几乎不可能同一时间同时故障。哪怕其中一个节点宕机或网络中断,Cloudflare 依然可以把回源请求自动调度到另一个节点,用户完全不会感知到后端出了什么问题。相比以前为了抗更多流量不得不加机器、调 PHP、装 Redis、到处插缓存插件的时代,这种架构已经轻松太多,也让运维的重心彻底转移到如何保持节点在线,而不再纠结怎么提升单机极限。
8 多活架构下的WordPress优化思路
8.1 碎碎念
在前面几章,其实已经把最核心的技术结构都搭建完成了:多节点 + Cloudflare Tunnel 的就近调度,rsync 的轻量同步,再加上 APO 直接把 HTML 推到边缘,让这个 WordPress 多活架构既分布式又高性能。
不过从技术角度来看,这其实只是”能用”。如果想要更优雅地长期运维下去,完全可以基于这个架构,针对多活场景进一步做减重、做云化、做自动化。
8.2 减重:不再需要传统的本地优化负担
在单节点时代,WordPress 的优化几乎是老生常谈:
- 本地安装 Redis / Memcached 做对象缓存
- W3TC、WP Rocket、Autoptimize 各种缓存插件层层叠加
- 还要小心别缓存过度,导致评论、分页、会话错乱
而现在的架构下访问流量几乎都被 APO 接管,HTML 页面直接在边缘返回,只有少量评论写入回源节点。这就意味着可以把 Redis、各种本地缓存插件都统统卸掉,PHP、Nginx 也不需要再为了抗压去做特殊调优。只需要保证 php-fpm 不会宕机就行。WordPress 变回了最纯粹的发布系统,机器负担小,维护难度更低。
8.3 云化:能交给 Cloudflare 的就不放在本地
既然都已经把站点多节点化了,很多以前本地强依赖的功能也可以顺势云化,比如:
- 第三方脚本交给 Zaraz:像 Google Analytics、百度统计、Hotjar 之类,可以统统塞进 Cloudflare Zaraz,不占用你自己的服务器连接数,也避免对访客直接曝光(参见文章:家庭数据中心系列 优化网站加载速度:通过 Cloudflare Zaraz 实现第三方脚本的云端加载及管理)。
- 图片、文件分发都从本地分离出去:比如使用Cloudflare R2作为图床(参见文章:家庭数据中心系列 cloudflare教程(八) CF R2功能介绍及基于R2搭建图床的详细教程);用 Worker替代之前本地实现的随机图片API(参见文章:家庭数据中心系列 构建高效且安全的随机图片API:Cloudflare Worker + R2 + KV 实战指南)。
- 文章阅读统计也放到 Worker:比自己写数据库表简单,避免数据写入再引发多节点同步问题(参见文章:家庭数据中心系列 Cloudflare Worker + KV:打造 WordPress 云端文章阅读统计)。
总之,把尽可能多的功能挪到 Cloudflare 层,就能让后端更干净。
8.4 自动化与可观测:运维少操心一点
多节点听上去很美,但日常维护显然比单节点麻烦:哪个节点死了?哪次同步失败了?评论写入是不是都正常?
如果手动盯着日志显然不现实,这里我主要利用了 Cloudflare 提供的运行状况检查(Health Checks)和通知(Notifications)功能,再结合自己搭建的 webhook(通过 Bark 推送到手机,技术细节可以参考文章:docker系列 搭建基于bark server的消息推送服务器),让多节点的监控更自动化。
- Cloudflare Health Checks:这项功能允许你直接在 Cloudflare 上配置 HTTP 检测,比如定时访问博客上的特定页面
https://blog.tangwudi.com/xxx,如果连续探测失败就会触发报警。 - Cloudflare Notifications:在面板上可以把健康检查和各种安全事件(WAF 被触发、IP 被封禁等)配置为事件源,支持通过邮件、Slack、Webhook 等方式发送告警。
- Webhook + Bark:我自己写了一个轻量的中转脚本,接收来自 Cloudflare Worker的 webhook通知,再转发到 Bark 实现 iPhone 通知;部分Cloudflare Notifications的事件可以直接通过bark通知到手机。
- Shell + 邮件 / Bark:本地的 rsync 同步脚本也做了简单的错误捕获,比如同步失败会自动再尝试几次,连续失败就通过邮件或者 Bark 提醒我。
这样做下来,哪怕多节点架构背后增加了复杂性,但在日常维护时几乎不用盯着,出了事第一时间就能在手机上收到推送。
这部分功能的具体实践可以参考文章:家庭数据中心系列 Cloudflare 监控告警组合实战:运行状况检查 + 事件警报带来的轻量化运维体验,文章前面的一些文章中也有涉及,不过有点散,毕竟运维需求到处都有。
9 多活架构的最后保险:静态站点兜底
说实话,对于一个没什么访问量小博客来说,搞什么 Cloudflare Tunnel 多活架构、APO 全球边缘缓存已经够“自我感动”了,结果还要再搞一层纯静态站点当作兜底,听上去简直就像在保障某种“金融核心业务系统”的连续可用性一样,多少有点中二。
但这其实不过是我个人的小执念罢了——都已经花了大半年时间一点点完善这套架构,既然可以再多做一步,为什么不索性连最极端的意外都一起兜住呢?
于是就有了这一步:使用 Simply Static插件 将 WordPress 全站生成纯静态页面,部署到 Cloudflare Pages,从而拥有一个即便数据库彻底挂掉、PHP 无法运行、Cloudflare Tunnel 全部失联,也仍然能正常提供阅读访问的最终保命方案。
如果未来某天真的不幸所有动态节点都出问题了,访客依然可以被部署在Cloudflare Pages上的静态版博客:https://staticblog.tangwudi.com接住,哪怕看不到最新评论、也发不了评论,总好过直接 502。
至于Simply Static插件的具体使用方式,我在另一篇文章里已经详细记录:家庭数据中心系列 WordPress网站通过Simply Static插件实现站点静态化,这里就不再赘述了。
10 总结
写到这里,基本就把我这大半年围绕 WordPress 多活架构的所有折腾都梳理完了:从最初只在家里 Mac mini 上单节点跑 WordPress,到被电信莫名其妙封网后,被逼在腾讯云轻量服务器上搞了个灾备节点;再到腾讯云服务器到期后因为昂贵的续费价格,索性迁移到Racknerd的芝加哥VPS节点,正式开始折腾双活。这一路走来,才逐渐有了如今这套基于 Cloudflare Tunnel 做全局就近分发、冗余回源节点、用 rsync 保证数据一致、再用 Worker 协调多点写入,最后再靠 APO 把 PHP 从用户访问链路中“摘出来”的完整架构:

它的本质,其实就是把那个曾经必须时刻在线的核心战斗单元——WordPress,变成了一个随时可以替换、一段时间掉线也不怕的冗余回源节点:哪怕 PHP 挂了,用户依旧能从 Cloudflare 的边缘节点读到完整页面,几乎察觉不到后端的异常;某个节点数据库崩了,或者 VPS 临时维护停机了,也只是稍后再同步修复的问题;就算偶尔评论写失败,也只是少数用户的小插曲,远比过去单节点模式下服务器一挂就心惊肉跳要从容得多。
想自己尝试搭建的朋友,可以直接参考我整理的方案架构和相关部署脚本,仓库地址是:https://github.com/tangwudi1979/multiwp-tunnel。
这篇文章只是我过去大半年不断踩坑、修正、折腾、探索的阶段性总结,是写给自己的一个交代。但也正因为有了这个“理想化目标”,我才能乐此不疲地一次次推倒重来,把那些原本模糊的细节逐步捋清,并在过程中顺便学会了更多底层网络、缓存一致性以及多活可用性的思路。或许这些方案对于绝大多数人并没有什么直接的借鉴意义,但对我来说,它就是一份真实的个人网络探索笔记,也算是这段时间里一个值得被记录的小里程碑。