WordPress + MySQL 在 Linux 环境下 CPU 持续飙高,是运维中最经典也最让人头秃的问题之一。这通常不是单一原因造成的,而是“动态内容生成”与“数据库查询效率”失衡的结果。
作为在云原生和传统架构领域摸爬滚打多年的技术人员,我将从快速止血(诊断)、核心优化(MySQL/PHP)、架构升级(缓存/CDN)三个层级,给你一套系统性的排查和解决方案。
第一阶段:快速定位——谁在吃 CPU?
不要盲目重启或加配置,先搞清楚瓶颈在哪里。登录服务器,执行以下操作:
1. 确定进程
top -c
# 或者更直观的 htop (推荐安装)
htop
观察 PID 对应的进程名:
- mysqld 占比高:数据库问题。
- php-fpm 或 nginx 占比高:PHP 代码执行慢或并发过高。
- apache2/lighttpd:如果是 Apache 模式,可能是 MPM 配置不当。
2. 查看负载来源
vmstat 1 5
iostat -x 1 5
如果 us (user space) 高,说明是 PHP/SQL 计算密集;如果 wa (iowait) 高,说明磁盘 IO 成为瓶颈(SSD 云服务器通常较少见此情况,除非日志写入极大)。
第二阶段:MySQL 深度优化(最常见瓶颈)
WordPress 的核心痛点在于低效的 SQL 查询。默认配置下,MySQL 很容易因为全表扫描而拖垮 CPU。
1. 开启慢查询日志 (Slow Query Log)
这是诊断的第一步。编辑 /etc/my.cnf 或 /etc/mysql/my.cnf:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 # 超过1秒的查询视为慢查询
log_queries_not_using_indexes = 1 # 记录未使用索引的查询
重启 MySQL 后,收集几小时的日志,用 mysqldumpslow 分析:
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
重点解决: 那些没有走索引(Using where, Without index)的查询。
2. 检查并优化索引
- 确保
wp_posts表的post_date,post_status,post_type有联合索引。 - 避免在
WHERE子句中对字段进行函数运算(如WHERE YEAR(post_date) = 2023),这会导致索引失效。 - 对于插件添加的表,务必检查是否有主键和常用查询字段的索引。
3. 调整 MySQL 关键参数 (针对 4G+ 内存服务器)
根据服务器内存大小调整 my.cnf:
# 缓冲池大小:设置为物理内存的 50%-70%
innodb_buffer_pool_size = 2G
# 连接数:根据 WordPress 并发量调整,不要设太大以免耗尽连接
max_connections = 200
# 临时表限制
tmp_table_size = 64M
max_heap_table_size = 64M
# 禁用 DNS 解析带来的延迟(重要!)
skip-name-resolve
4. 清理垃圾数据
- 定期清理
wp_postmeta中未被引用的元数据。 - 清空回收站文章、自动草稿(Autosave)、修订版本(Revisions)。
- 插件建议安装 WP-Optimize 或手动执行 SQL 清理旧评论 Spam。
第三阶段:PHP 与应用层优化
1. PHP-FPM 调优
如果使用 Nginx + PHP-FPM,检查 /etc/php/*/fpm/pool.d/www.conf:
; 静态模式 vs 动态模式
; 如果并发稳定,设为 static,性能更好
pm = dynamic
; 最小空闲进程数
pm.min_spare_servers = 5
; 最大空闲进程数
pm.max_spare_servers = 20
; 最大进程数(根据 CPU 核心数和内存调整,每个 PHP 进程约 50-100MB 内存)
pm.max_children = 50
注意: pm.max_children 不能超过服务器总内存 / 单个 PHP 进程平均内存。否则会导致 Swap 交换,CPU 飙升且响应极慢。
2. PHP 版本升级
- 确保使用 PHP 8.1 或更高版本。PHP 8 相比 7.x 在 JIT 编译和内存管理上有显著提升,WordPress 运行效率可提高 20%-30%。
- 启用 OPcache:确保
php.ini中opcache.enable=1,并合理设置opcache.memory_consumption(建议 128M+)。
3. 代码层面优化
- 禁用自举循环 (Infinite Loops):某些劣质插件会在后台不断请求 API 或执行定时任务。
- 关闭 REST API 心跳:如果不需要移动端同步,可禁用
heartbeat。 - 图片懒加载:确保所有图片使用
<img loading="lazy">。
第四阶段:架构级解耦(终极方案)
如果上述优化后 CPU 依然高,说明你的架构无法承受当前流量,需要引入缓存层。
1. 全站缓存 (Page Cache)
- 对象缓存 (Object Cache):必须上 Redis 或 Memcached。
- 安装 Redis 服务。
- WordPress 安装 Redis Object Cache 插件。
- 这将把频繁查询的用户会话、选项、菜单等存入内存,大幅减少 MySQL 查询次数。
- 页面缓存 (Page Cache):
- 使用 W3 Total Cache、WP Super Cache 或 LiteSpeed Cache(如果你用 LiteSpeed Web Server)。
- 生成静态 HTML 文件,直接由 Nginx/Apache 返回,跳过 PHP 和 MySQL。
2. CDN 提速
- 将静态资源(JS, CSS, Images)全部推送到 CDN(如阿里云 CDN、腾讯云 CDN、Cloudflare)。
- 配置回源规则,只让动态请求到达源站。
- 效果:90% 的请求被 CDN 拦截,源站 CPU 压力骤降。
3. 动静分离
- 确保 Nginx 配置中,静态文件过期时间设长(如 30 天),并启用 Gzip/Brotli 压缩。
第五阶段:云平台特定建议(国内厂商)
既然你熟悉国内云厂商,这里有一些针对性建议:
-
RDS 替代自建 MySQL:
- 如果业务增长,强烈建议迁移到阿里云 RDS MySQL 或腾讯云 CDB。
- 云数据库提供了自动备份、慢查询分析、SQL 审计、高性能引擎优化,且通过内网访问零延迟。
- 选择 ESSD 云盘,IOPS 稳定性远高于本地 SSD。
-
弹性伸缩 (Auto Scaling):
- 在阿里云 ECS 或腾讯云 CVM 上配置自动伸缩组。
- 当 CPU > 70% 持续时间超过 5 分钟时,自动增加实例;低于 30% 时自动释放。
- 配合 SLB(负载均衡)实现高可用。
-
Serverless 架构探索:
- 对于流量波动大的博客或中小网站,考虑 函数计算 FC + API 网关 + 云数据库。
- 按调用付费,无请求时费用为零,彻底解决 CPU 闲置浪费和峰值扛不住的问题。
总结行动清单
- 立即:开启 MySQL 慢查询日志,找出最耗资源的 SQL。
- 短期:升级 PHP 到 8.1+,启用 OPcache,配置 Redis 对象缓存。
- 中期:清理 WordPress 数据库垃圾,优化索引,调整 PHP-FPM 进程数。
- 长期:接入 CDN,迁移至云数据库 RDS,或采用 Serverless 架构。
最后提醒:任何生产环境修改前,请先备份数据库和网站文件!可以使用 mysqldump 和 rsync 或云厂商自带的快照功能。
云计算导航