【VPS 进阶玩法精选 026】VPS 上 WordPress 提速:缓存、对象存储与数据库优化

同样的 VPS,别人站点 200ms 你却 3s?从 TTFB 瓶颈定位、OPcache、页面缓存、Redis 对象缓存,到图片/CDN 与数据库索引,系统性把首字节时间压下来。

专题连载:VPS 进阶玩法精选

本文是该系列第 26 篇。阅读该系列其他文章:

你有没有遇到过这种情况:和朋友买了同一款便宜 VPS,配置看起来一模一样,他博客打开"唰"地一下就出来了,你自己的 WordPress 后台转圈圈,前台首屏愣是 3 秒才出第一个字。问题往往不在机器本身,而在默认装完的那套 LNMP 几乎没调过——PHP 每次请求都现场编译一遍、页面每次都现查数据库、图片还是三年前的原图没动过。本文就按"从最划算到最费劲"的顺序,把 TTFB(首字节时间)一层层往下压,让你手里这台小鸡发挥出该有的性能。

延伸阅读

更多相关攻略推荐:Ollama AI系列(2):VPS上的AI推理与API应用Ollama AI系列(2):VPS上的AI推理与API应用【CPU选型 01】搭载 AMD Ryzen 9950X 的 VPSARM / Ampere 席卷 VPS:性价比真香还是兼容陷阱?Ollama AI系列(2):VPS上的AI推理与API应用

一、先定位瓶颈:TTFB 与测速工具

动手优化之前先测,别凭感觉瞎调。TTFB(Time To First Byte)是浏览器收到服务器第一个字节的时间,它最能反映"服务端到底慢不慢"。静态资源体积再大,只要 CDN 兜得住,对首屏文字出现影响有限;真正拖后腿的永远是动态 PHP 请求。常用工具:WebPageTest、GTmetrix、PageSpeed Insights,以及最朴素的命令行 curl 直接测 TTFB:

curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" https://你的域名.com

第一轮访问是冷缓存,多测几次取稳定值。经验线:未缓存页面 TTFB 大于 1.5 秒,基本是 PHP 或数据库瓶颈;已缓存页面还慢,优先查 CDN 回源和 DNS 解析。WordPress 后端再装一个 Query Monitor 插件,能直接看到每个请求打了多少条 SQL、哪个插件最耗时,比盲猜高效得多。

顺带提一句 Core Web Vitals:LCP(最大内容绘制)看首屏主图何时出现,INP(交互延迟)看点击到响应的流畅度。TTFB 是这两者的地基——地基没打好,前端再怎么压缩都救不回整体体验。WebPageTest 的 Waterfall 视图能看清是哪个请求在排队,是 SSL 握手慢还是数据库查询卡住,定位比凭感觉准得多。

二、OPcache 与 PHP-FPM 调优

PHP 是解释型语言,每来一个请求,默认要把 .php 文件先编译成字节码再执行。WordPress 这种动辄上万文件的项目,光编译开销就够喝一壶。OPcache 把编译结果缓存进共享内存,第二次起直接跳过编译,官方数据能砍掉一半 PHP 执行时间。php.ini 生产环境推荐配置:

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.revalidate_freq=60

注意 validate_timestamps=0 表示不自动检查文件改动,部署代码后必须手动重置 OPcache(重启 php-fpm 或调用重置接口),否则你改了代码线上不生效,这种坑踩过一次就忘不了。PHP 版本本身也很关键:PHP 8.1/8.2 比 7.4 吞吐高 15%–20%,老版本还早已停止安全更新。PHP-FPM 进程池方面,内存紧张就选 pm=ondemand 或 pm=dynamic,max_children 按"可用内存 ÷ 单进程内存"算,别拍脑袋设很大,否则流量一上来直接 OOM 把机器拖死。

上线前用 php -i | grep opcache.enable 确认是 On,再看 interned_strings_buffer 是否生效。这个参数存的是重复字符串(类名、变量名)的共享副本,WordPress 这种大项目设 8–16 更稳,能少占不少重复内存。记住:OPcache 只缓存字节码、不缓存数据,所以它和下面的 Redis 对象缓存是两层完全不同的东西,别混为一谈。

三、页面缓存:Nginx 快取或缓存插件

页面缓存是性价比最高的一层:把整页渲染好的 HTML 存起来,匿名访客再来直接吐文件,PHP 和 MySQL 全程不启动。两条路子:一是缓存插件,比如 WP Super Cache、WP Rocket、LiteSpeed Cache,开箱即用,适合不想碰配置的;二是 Nginx fastcgi_cache,在 Web 服务器层就搞定,请求根本不进 PHP,效率最高。核心思路是给匿名用户命中缓存,登录用户、后台、wp-login、带查询参数的请求则跳过:

location ~ \.php$ {
    fastcgi_cache WORDPRESS;
    fastcgi_cache_valid 200 302 1h;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    add_header X-FastCGI-Cache $upstream_cache_status;
}

用 curl 看响应头里的 X-FastCGI-Cache: HIT 就说明命中了。发布文章时要配置自动清缓存,否则读者会看到旧页面。实测中,Redis 对象缓存加 Nginx 页面缓存这一套组合,能把 TTFB 从 2 秒量级压到 0.3 秒左右。

快取还有个细节:用 cookie 区分登录态,给已登录用户打上跳过标记,避免把"管理员看到的页面"缓存下来发给普通访客这种乌龙。命中之后也别忘了 Purge——装一个能监听 WordPress 发布事件的清缓存插件,文章一更新边缘节点自动失效,否则前台挂着旧稿很尴尬。Nginx 快取和插件二选一即可,两套同时开容易互相打架、命中率算不清。

四、Redis 对象缓存

页面缓存照顾的是匿名访客,但登录用户、WP-Cron 定时任务、后台操作,以及插件反复查询的那部分数据,页面缓存管不到,得靠对象缓存。Redis 把常用的数据库查询结果、transient(瞬时数据)、选项表塞进内存,下次请求直接内存里拿,省掉大量重复 SQL。WordPress 装上 Redis Object Cache 插件,wp-config.php 里定义 WP_CACHE 并配好连接即可;一台机器上跑多个站点时,记得每个站用不同的 database 编号,避免数据串味。Redis 自己也要设上限和淘汰策略,别让它无限吃内存:

maxmemory 128mb
maxmemory-policy allkeys-lru

对象缓存加页面缓存,是 VPS 上 WordPress 提速的黄金组合。匿名流量走页面缓存几乎零成本,登录态和动态片段走 Redis,数据库压力能降七八成。

五、图片优化与 CDN 分流

图片往往是页面体积的大头,经常占掉总重量的六成以上。第一步转格式:WebP 或 AVIF,同等画质比 JPEG 小 25%–35%,很多缓存插件(如 LiteSpeed Cache、ShortPixel)能批量转。第二步懒加载,原生 loading="lazy" 就够,不必专门装插件。第三步用 CDN 把静态资源推到离访客最近的边缘节点,Cloudflare 免费版足以:开 Auto Minify、Brotli 压缩、标准缓存级别。对异地访客,CDN 能把 TTFB 再降 40%–60%。同时别忘了在 Nginx 给静态资源设长缓存,让回访者直接读本地:

location ~* \.(js|css|png|jpg|webp)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

六、数据库索引与慢查询排查

WordPress 慢,十有八九跟数据库有关。先清 autoload(自动加载)数据:wp_options 表里标了 autoload=yes 的选项,每个请求都会整表读进内存,总量超过 800KB 就明显拖慢,用 WP-Optimize 插件或一条 SQL 清理掉长期不用的大选项。再开慢查询日志抓真凶:

slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1

让它跑一两天,用 mysqldumpslow 找出最慢的语句,拿 EXPLAIN 看执行计划。如果 type=ALL 或者扫描行数特别高,就是全表扫描,给 WHERE、JOIN、ORDER BY 用到的列加复合索引即可。顺手把 wp_post_revisions 限制到 3–5 个,别让文章修订版堆成山。InnoDB 引擎下,把 innodb_buffer_pool_size 设到可用内存的 50%–70%(与 Web 同机则降到 256M 左右,详见下一篇),命中率上去了磁盘 IO 自然下来。

还有一类常被忽略的拖累:transient(瞬时数据)。很多插件把临时结果写进数据库,到期不清理就常驻,越积越多。用 WP-CLI 一条命令就能批量清:wp transient delete --expired。再配合 WP-Optimize 定期删垃圾评论、孤儿元数据和过期的文章修订,表瘦身之后查询明显轻快。记住索引是治本、清理是治标,两件事一起做才稳。

七、小内存 VPS 的取舍

512M 到 1G 的小鸡跑 WordPress,资源要算细账。OPcache 留 64–128M,Redis 留 64–128M,PHP-FPM 进程数按内存反推,MySQL 的 buffer pool 压到 256M 左右。能静态化的尽量静态化,把站内搜索、访问统计这类重活外包给第三方服务或 CDN,别全压在数据库上。关闭 WordPress 自带的 WP-Cron,改用系统 cron 每分钟触发一次,避免每次访问都顺带跑定时任务。精简插件,那种塞一堆前端脚本和数据库查询的"瑞士军刀"插件最该清理。真扛不住稳定流量时,升到 2G 内存往往比在 512M 上反复折腾更划算——省钱省心还少宕机。

判断要不要升配有个简单信号:连续多天 free -h 里 available 长期低于 10%,或 MySQL 慢查询日志里开始出现大量因内存不足导致的临时表落盘,就该加内存了。升到 2G 后,buffer pool 能放开到 512M–1G,命中率一上去,原本要 2 秒的查询可能 200 毫秒就回,这是质的提升,而不是在 512M 上靠关这个关那个硬撑。把预算花在刀刃上,比花在救火上值。

💡 延伸阅读:关于架构与基础设施的更多深潜指南,请前往 VPS 主题导读中心 (Hub) 获取全盘策略。