Nginx + PHP-FPM + MySQL部署WordPress后MySQL CPU占用异常如何诊断?

当 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 → 内存不足导致频繁磁盘 IO
  • max_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; }
防止后台被刷爆

📊 四、长效监控建议

  1. 部署 Prometheus + Grafana:监控 mysql_global_status_threads_running, mysql_info_schema_innodb_row_ops
  2. 每日慢查询报告:用脚本自动分析慢日志并邮件告警
  3. 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 » Nginx + PHP-FPM + MySQL部署WordPress后MySQL CPU占用异常如何诊断?