摘要

WordPress 博客(028000.xyz,Sakurairo 主题)曾经首页 HTML 234KB、Hero 视频 26MB,打开慢到自己都嫌弃。这篇记录一次"极致"速度优化:先测基线,再按层动手——nginx(HTTP/2、gzip、静态缓存)、PHP-FPM(ondemand→dynamic)、MySQL(buffer_pool 16M→128M)、Redis 对象缓存(命中率~81%)、前端(视频压缩、s.nmxc.ltd 本地化、HTML 瘦身)。最终首页 HTML 234KB→96KB(gzip 后 22KB),本机缓存命中 11ms。记住优化的铁律:先测基线,每做一步测一次,别一次改完再找是谁的功劳。

目录

一、优化前的基线:先测再动

优化前先测,记下来,这是基线:

指标 优化前
首页 HTML 234KB
Hero 视频 26MB
封面图 8 张 JPG,共 6.1MB
外部引用 s.nmxc.ltd 30 处
TTFB(外部) 慢,体感明显

优化的铁律:先测基线,每做一步测一次。一次改十处,最后快了也不知道是谁的功劳;慢了更不知道回滚哪一处。基线是所有对比的锚点。

二、nginx 层:HTTP/2、gzip、静态缓存

# 关键配置
listen 443 ssl http2;           # HTTP/2
gzip on;
gzip_comp_level 6;              # gzip 6 级(压缩率与 CPU 的平衡点)

# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|webp)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}
location ~* \.(woff|woff2|ttf)$ {
    expires 365d;               # 字体一年
}
location ~* \.(mp4|webm)$ {
    expires 7d;                 # 视频 7 天
}

TLS 只开 1.2/1.3(和全家统一)。gzip 6 级是压缩率和 CPU 消耗的平衡点,再高收益递减。静态资源按类型设不同的过期:图片 30 天、字体 365 天(字体几乎不变)、视频 7 天。

三、PHP-FPM:ondemand→dynamic

PHP-FPM 的进程管理模式从 ondemand 改成 dynamic:

; php-fpm 配置
pm = dynamic
pm.max_children = 8
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4

ondemand 是"来请求才 fork 进程",每个请求都要付进程创建的成本;dynamic 常驻 2 个进程,请求来了直接用。博客这种持续有请求的场景,dynamic 的响应更稳。注意改完要 systemctl reload php-fpm-82,而且OPcache 会缓存旧页面,部署后如果页面没变化,先 reload php-fpm 再怀疑人生。

四、MySQL:buffer_pool 16M→128M

# my.cnf
innodb_buffer_pool_size = 128M   # 原 16M

16M 的 buffer_pool,稍微大点的查询就全是磁盘 IO。128M 对这个量级的博客够用了,VPS 内存只有约 1 GiB,不能再大。MySQL 调优的原则:够用就好,内存是全家最缺的资源。

五、Redis 对象缓存:命中率 81%

装 Redis 8.0.2 做对象缓存,64M,专用 redis-blog.service,phpredis 6.3.0:

指标 数值
Redis 版本 8.0.2
内存 64M
PHP 扩展 phpredis 6.3.0
命中率 ~81%

81% 的命中率意味着 8 成的数据库查询被缓存挡掉了,剩下的 2 成才是真的查库。对象缓存和页面缓存分工不同:页面缓存(WP Fastest Cache)存整页 HTML,对象缓存存数据库查询结果,两层叠加。验证命中率:Redis 的 INFO stats 看 keyspace_hits/keyspace_misses,算一下就知道。

六、前端:视频、字体、HTML 瘦身

前端是"体感最明显"的一层:

优化项 优化前 优化后
Hero 视频 26MB 8.8MB(H.264 CRF26 720p)+ preload=metadata + 移动端不加载
封面图 8 张 JPG 6.1MB WebP 2.6MB(原图备份 /www/backup/media-orig-20260930/)
外部引用 s.nmxc.ltd 30 处 0(彻底本地化)
首页 HTML 234KB 96KB(gzip 后 22KB)

几个细节:视频用 H.264 CRF26 转 720p,体积从 26MB 压到 8.8MB,preload=metadata 让浏览器先只加载元数据,移动端直接不加载视频(手机上 Hero 视频是纯负担)。s.nmxc.ltd 的 30 处引用全部本地化,外部依赖清零,页面不再被第三方拖慢。Heartbeat 前台禁用、后台 60s,减少 admin-ajax 的无谓请求。

封面图转 WebP 时,原图备份在 /www/backup/media-orig-20260930/,主题选项里的 URL 同步更新。图片优化永远保留原图,WebP 出问题能回滚。

七、插件分工:谁干什么别打架

插件 职责
WP Fastest Cache 页面缓存
Autoptimize HTML/CSS/JS 压缩合并
WP-Optimize 数据库优化(transient 清理、表优化)

WP-Optimize 的 HTML/CSS/JS 压缩要关掉,因为和 Autoptimize 重复了。两个插件同时压缩,轻则浪费 CPU,重则互相打架出乱码。插件分工的原则:一个职责只给一个插件,功能重叠的只留一个。

八、最终成绩单

指标 优化前 优化后
首页 HTML 234KB 96KB(gzip 22KB)
Hero 视频 26MB 8.8MB
封面图 6.1MB JPG 2.6MB WebP
外部引用 30 处 0
本机缓存命中 — 11ms
本机动态 — 0.33s
外部 TTFB 慢 ~0.9-1.1s(瓶颈在法兰克福网络路径,非服务器)

外部 TTFB 的瓶颈在法兰克福的网络路径,不是服务器性能,这一点要认清楚:优化到网络瓶颈就收手,再往下是运营商的事。当时还出了份 Word 版报告归档。

九、踩坑记录

坑 1:OPcache 导致部署后页面不变

改完 PHP 或主题,页面还是旧的,第一反应是"缓存插件没清"。其实是 PHP-FPM 的 OPcache。解法:systemctl reload php-fpm-82。以后部署后页面不变,先 reload php-fpm,再查别的缓存。

坑 2:两个压缩插件打架

WP-Optimize 和 Autoptimize 都有 HTML/CSS/JS 压缩,同时开会冲突。解法:WP-Optimize 只留数据库优化,压缩全给 Autoptimize。教训:装插件前先看功能是否重叠。

坑 3:父主题改动升级会被覆盖

theme-plus.php 的改动记在子主题里,别直接改父主题。WordPress 主题升级会覆盖父主题文件,直接改等于白干。子主题(sakurairo-child)就是干这个的:custom.css、custom.js、功能覆盖全放子主题。

坑 4:CDN 的取舍

当时定了上 Cloudflare 免费版(SSL Full Strict + 静态边缘缓存 + wp-admin 不缓存 + Brotli/HTTP3),卡在等用户定注册邮箱。CDN 是"网络瓶颈"的解法,服务器优化到头了,剩下的交给边缘节点。注意 nps 管理面板直连不走 CDN。

瀑布图解读:时间花在哪了

优化时看瀑布图(浏览器开发者工具 → Network),时间花在哪一目了然:

阶段 看什么 优化前的问题
DNS + 建连 + TLS 域名解析和握手时间 外部 TTFB 高,瓶颈在法兰克福路径
首字节(TTFB) 服务器生成 HTML 的时间 PHP-FPM ondemand、MySQL buffer 小
内容下载 HTML/JS/CSS/图片的体积 234KB HTML、6.1MB 封面、26MB 视频
第三方 外部域名的请求 s.nmxc.ltd 30 处引用

瀑布图是优化的"地图":哪一段最长,就先动哪一段。别凭感觉优化,感觉会骗人,瀑布图不会。

持续监控:别让优化成果滑坡

优化完不是一劳永逸,装个新插件、换张大封面,成绩就滑回去了。防滑坡三件套:

  1. 定期测:每月跑一次首页加载测试,记下 TTFB 和 HTML 体积,和基线对比;
  2. 传图规范:封面图先转 WebP 再传,别直接丢 5MB 的原图上去;
  3. 插件审计:每季度看一次插件列表,停用的删掉,功能重叠的只留一个。

性能是"熵增"的,维护是"做功"。不维护的优化,半年后打回原形。

性能优化的终点:够用就好

优化做到最后,会遇到一个问题:什么时候停?首页 96KB 了,要不要压到 80KB?TTFB 0.4s 了,要不要压到 0.2s?答案是:够用就好。优化的终点不是"最快",是"快到用户感知不到慢"。

感知阈值:页面 1 秒内打开,用户觉得"快";1-3 秒,"能接受";3 秒以上,"慢"。从 5 秒优化到 1 秒,体感天差地别;从 1 秒优化到 0.5 秒,用户基本无感。优化的投入产出比,在 1 秒附近断崖式下跌。所以优化目标定在"1 秒内",到了就收手,剩下的时间干点别的。

优化的成本:每次优化都有成本。Redis 多占 64M 内存,页面缓存多占磁盘,Autoptimize 的合并多一次构建。成本不只是资源,还有复杂度:缓存层越多,"改了没生效"的排查越难(OPcache、页面缓存、CDN 缓存,三层套娃)。优化是加法,排查是乘法。够用就好,也是给未来的自己减负。

优化的敌人:最大的敌人不是"慢",是"滑坡"。新插件、超大封面、第三方统计代码,悄悄把成绩吃回去。所以"持续监控"那节比"优化清单"更重要。优化是一次性的,防滑坡是长期的。把"每月测一次"写进日历,比把"首页压到 80KB"有价值得多。

最后,性能优化的最高境界:用户不需要知道你优化过。页面打开就是快,没有加载动画,没有"正在优化中"的提示。好的优化是隐形的,就像好的基础设施——没人注意到它,恰恰说明它工作得很好。

缓存的层次:从浏览器到 CDN

这篇讲了页面缓存(WP Fastest Cache)、对象缓存(Redis)、OPcache,漏了一层:浏览器缓存,和再往外一层:CDN。缓存是分层的,每层挡掉一部分请求。

用户 ←→ CDN(边缘) ←→ nginx(静态) ←→ 页面缓存 ←→ PHP+OPcache ←→ Redis ←→ MySQL
  快 ←——————————————————————————————————————————————————————————————→ 慢

浏览器缓存:静态资源(图片、CSS、JS)设长过期,浏览器第二次打开不请求了。这是最快的缓存,因为"不请求"比"请求了命中"还快。版本号策略:文件名带 hash(style.abc123.css),更新即换名,缓存永不过期。这是前端构建的常规操作。

CDN:Cloudflare 免费版,把静态资源推到边缘节点。用户在广东,请求到香港节点,不用跑到法兰克福。这是"网络瓶颈"的解法:服务器再快,跨国线路的物理延迟摆在那。CDN 把内容搬到用户旁边,延迟从 900ms 降到 50ms。动态内容(wp-admin、登录)不缓存,只缓存静态。

层次的原则:越靠近用户,越快,越便宜(不消耗源站资源)。优化时,从外往里配:浏览器缓存 → CDN → nginx 静态 → 页面缓存 → 对象缓存。外层命中了,内层不工作,省资源。缓存命中率,每层单独看:浏览器看 Network 的 (from disk cache),CDN 看 HIT/MISS 头,页面缓存看响应头,Redis 看 INFO。

缓存的代价:每一层都是"一致性"的妥协。缓存了,就有"过期"问题:文章更新了,CDN 还是旧的。解法是"主动 purge":发布文章时,调 Cloudflare API 清缓存;或者设短过期(HTML 不缓存,只缓存静态)。动态和静态分开:HTML 走页面缓存(短),静态走 CDN(长)。分开,才能各取所需。

缓存的层次配齐,博客的访问链条就是:用户 → 边缘命中(快)→ 未命中 → 源站层层挡 → MySQL(最后手段)。大部分请求在边缘就结束了,源站很闲。闲的服务器,才是快的服务器。

HTTP/3:下一步

nginx 配好 HTTP/2,下一步是 HTTP/3(QUIC)。Cloudflare 的方案里,HTTP/3 是标配(开一下就行);自建 nginx,HTTP/3 要较新的版本 + QUIC 支持。HTTP/3 的价值:弱网下更快(0-RTT、连接迁移),手机上刷博客,体感提升明显。

但 HTTP/3 不是"开了就快":UDP 443 要在防火墙放行,中间设备(运营商)对 UDP 的限速可能抵消收益。尝鲜可以,生产先观望。优化的节奏:HTTP/2 先吃透,CDN 先上好,HTTP/3 排队。技术追新,永远排在"稳定"后面。 WordPress 优化到这,服务器这头的事做完了。剩下的路在 CDN 和网络,该交棒了。优化有终点,够用就好。记住感知阈值:1 秒内快,1-3 秒能接受,3 秒以上慢。到了 1 秒内,就收手,剩下的时间写文章去。性能是手段,内容才是目的,别把手段当成目的。优化到 1 秒内,剩下的精力,给内容。读者为内容来,不是为 TTFB 来。TTFB 是门面,内容是里子。门面收拾到 1 秒内,里子慢慢写。

另外,优化报告(Word 版)归档在 NAS,数字都在里面。这篇是"怎么做",报告是"做到了多少",两个配合看。 优化的最后一块拼图是"测量"。没测量的优化,是玄学。每次改完,测三组数:首页 HTML 大小(curl 看 Content-Length)、TTFB(curl -w 看 time_starttransfer)、Lighthouse 跑分。记下来,和上次对比。数字涨了,优化有效;数字没动,改动白费。优化的习惯是"改一次,测一次,记一次"。这篇讲的每个手段,都值得这样验证一遍。验证完了,这篇的使命就完成了。使命完成,工具收好,下一篇见。优化是手段,写文章才是正事。正事要紧,手段够用就行。够用,就收手。

十、总结

WordPress 优化是分层工程:nginx(HTTP/2、gzip、静态缓存)→ PHP-FPM(dynamic)→ MySQL(buffer_pool)→ Redis(对象缓存 81%)→ 前端(视频/图片/外部引用/HTML 瘦身)→ 插件分工(不打架)。每层做完测一次,基线对比。最终首页 234KB→96KB(gzip 22KB),本机 11ms。记住:优化到网络瓶颈就收手;OPcache 是部署后的第一嫌疑人;父主题别直接改。

相关阅读:《Halo 博客从零搭建:2.26.1 + Hao 主题全记录》。