当 Nginx + PHP-FPM + MySQL 部署 WordPress 后出现 MySQL CPU 占用异常高(如持续 >80%、频繁 100%),需系统性诊断。以下是专业、可落地的分步排查与优化指南(兼顾安全、性能与可维护性):
🔍 一、快速确认现象与基线(5 分钟)
# 1. 查看实时 CPU 占用(确认是否确实是 mysqld 进程)
top -c | grep mysqld
# 2. 获取 MySQL 当前活跃连接与状态
mysql -u root -p -e "SHOW PROCESSLIST;"
# 3. 检查 MySQL 全局状态(重点关注 Threads_running, Questions, Slow_queries)
mysql -u root -p -e "SHOW GLOBAL STATUS LIKE 'Threads_running';"
mysql -u root -p -e "SHOW GLOBAL STATUS LIKE 'Questions';"
mysql -u root -p -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';"
✅ 关键指标阈值参考:
Threads_running > 10→ 并发过高Slow_queries > 0且增长快 → 慢查询积压Questions每秒突增(对比历史基线)→ 可能遭遇爬虫/攻击/插件失控
🧩 二、精准定位根因(核心步骤)
✅ 1. 捕获高负载时段的慢查询(最常见原因)
# 启用慢查询日志(临时生效,避免重启)
mysql -u root -p -e "
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; # 记录 >1s 查询(WordPress 建议设为 0.5~2s)
SET GLOBAL log_queries_not_using_indexes = ON; -- 警惕全表扫描
"
# 实时监控慢查询(另开终端)
tail -f /var/lib/mysql/slow.log # 路径依 my.cnf 中 slow_query_log_file 配置而定
📌 重点分析:
- 是否大量
SELECT * FROM wp_posts WHERE post_status = 'publish' ORDER BY post_date DESC LIMIT 10?→ 缺少索引 - 是否频繁执行
wp_options表的SELECT option_value FROM wp_options WHERE option_name = '...';?→ 缓存失效或插件反复读取 - 是否存在
JOIN wp_posts p JOIN wp_postmeta pm ...无索引关联?→ 经典 WordPress 性能陷阱
💡 技巧:用
pt-query-digest(Percona Toolkit)分析慢日志:pt-query-digest /var/lib/mysql/slow.log --limit 10
✅ 2. 检查 WordPress 特有瓶颈
| 场景 | 诊断命令 | 解决方案 |
|---|---|---|
| 插件/主题引发高频查询 | mysql -e "SELECT * FROM wp_options WHERE option_name LIKE '%transient%' OR option_name LIKE '%cache%';" |
禁用插件逐个测试;启用对象缓存(Redis/Memcached) |
| WP-Cron 被前台触发 | curl -I https://yoursite.com/wp-cron.php(检查响应头 X-WP-Cron) |
在 wp-config.php 添加 define('DISABLE_WP_CRON', true);,改用系统 cron:*/15 * * * * curl -s https://yoursite.com/wp-cron.php >/dev/null 2>&1 |
| 未优化的查询(如 WP_Query) | 安装 Query Monitor 插件 | 查看每页 SQL 执行数、耗时、未使用索引的查询 |
✅ 3. MySQL 配置与资源瓶颈
# 检查关键配置是否合理(对比官方推荐)
mysql -u root -p -e "
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'query_cache_type'; -- ⚠️ MySQL 8.0+ 已移除!若启用则禁用
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'tmp_table_size';
"
🔧 常见错误配置:
innodb_buffer_pool_size < 50% of RAM→ 内存不足导致频繁磁盘 IOmax_connections过小(如默认 151)→ 连接排队,CPU 空转等待- 误启 Query Cache(MySQL 5.7 及以下)→ 高并发下锁竞争严重,务必关闭:
SET GLOBAL query_cache_type = OFF; SET GLOBAL query_cache_size = 0;
✅ 4. 外部因素排查
- 恶意爬虫/CC 攻击:
# 检查 Nginx 日志高频 IP(1 分钟内请求 >100 次) awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20 - 数据库被其他服务滥用:确认无其他应用共享同一 MySQL 实例
- 硬件问题:
iostat -x 1查看await(IO 等待)是否 >100ms → 磁盘瓶颈(SSD vs HDD)
🚀 三、针对性优化(立即生效)
✅ 1. 紧急缓解措施
-- 临时终止长期运行的查询(谨慎!)
SHOW PROCESSLIST;
KILL <ID>; -- 替换为实际 ID
-- 清理过期 transient(WordPress 自动清理可能失效)
DELETE FROM wp_options WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP(NOW() - INTERVAL 1 HOUR);
DELETE FROM wp_options WHERE option_name LIKE '_transient_%' AND option_name NOT LIKE '_transient_timeout_%';
✅ 2. 必须添加的索引(WordPress 核心优化)
-- 提速文章查询(post_status + post_date 复合索引)
ALTER TABLE wp_posts ADD INDEX idx_status_date (post_status, post_date);
-- 提速 meta 查询(常见于 WooCommerce/SEO 插件)
ALTER TABLE wp_postmeta ADD INDEX idx_post_id_meta_key (post_id, meta_key);
-- 提速评论查询
ALTER TABLE wp_comments ADD INDEX idx_comment_approved_date (comment_approved, comment_date_gmt);
✅ 3. 生产环境必备加固
| 方案 | 配置示例 | 效果 |
|---|---|---|
| 启用 Redis 对象缓存 | 安装 Redis Object Cache 插件,配置 wp-config.php:define('WP_REDIS_HOST', '127.0.0.1'); |
减少 70%+ wp_options 查询 |
| Nginx 静态资源缓存 | 在 server 块中添加:location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } |
降低 PHP-FPM 和 MySQL 压力 |
| 限制爬虫频率 | Nginx 配置限速:limit_req_zone $binary_remote_addr zone=wp:10m rate=2r/s;location ~ /wp-admin/ { limit_req zone=wp burst=5 nodelay; } |
防止后台被刷爆 |
📊 四、长效监控建议
- 部署 Prometheus + Grafana:监控
mysql_global_status_threads_running,mysql_info_schema_innodb_row_ops - 每日慢查询报告:用脚本自动分析慢日志并邮件告警
- WordPress 健康检查:定期运行
wp db optimize(需 WP-CLI)和wp rewrite structure '/%postname%/'(确保重写规则高效)
❌ 常见误区(避坑指南)
- × 盲目增加
innodb_buffer_pool_size→ 导致系统内存不足,触发 OOM Killer - × 在
wp_options表加全文索引 → 该表设计不适合全文搜索,应改用 Elasticsearch - × 使用
wp super cache但未排除动态页面(如购物车)→ 缓存失效反而加重 DB 负担 - × 忽略 MySQL 错误日志(
/var/log/mysql/error.log)→ 关键线索常在此处
✅ 总结:处理流程图
graph LR
A[发现 MySQL CPU 高] --> B{是否慢查询?}
B -->|是| C[分析 slow.log → 优化 SQL/加索引]
B -->|否| D{是否连接数暴增?}
D -->|是| E[检查爬虫/攻击/插件失控]
D -->|否| F{是否配置不当?}
F -->|是| G[调优 innodb_buffer_pool / max_connections]
F -->|否| H[检查硬件/其他服务干扰]
C --> I[部署 Redis 缓存]
E --> I
G --> I
I --> J[持续监控验证效果]
💡 终极建议:对生产环境,永远先备份再操作(
mysqldump --single-transaction wp_db > backup.sql),并选择业务低峰期执行优化。
如需进一步分析,请提供:
① SHOW PROCESSLIST 输出片段
② slow.log 中 2~3 条典型慢查询
③ my.cnf 中 [mysqld] 关键参数(innodb_buffer_pool_size, max_connections 等)
我可为你定制优化方案。
云知道CLOUD