My Computer · 2025/05/29 0

苹果CMS V10 mysql数据库联合索引和PHP-FPM 配置优化 解决mysql,php-fpm瞬时cpu占用99%

苹果CMS V10迁移到新服务器mysql、php-fpm资源占用异常

1、数据库优化

分析了下慢日志存在严重的重复高耗时查询问题

SELECT type_id_1,type_id,count(vod_id) as cc 
FROM mac_vod 
WHERE vod_status = 1 
GROUP BY type_id_1, type_id;

该语句在 短时间内被重复执行了十多次,并且每次都耗时 3~8 秒不等

Rows_examined: 120543

每次查询都扫描了 12 万+行,说明没有使用有效索引。

该查询中使用了 WHERE vod_status = 1,再对 (type_id_1, type_id) 分组。如果没有组合索引 (vod_status, type_id_1, type_id),这个查询将导致全表扫描。

✅ 建议:建立合适的组合索引

建议添加以下索引来显著加速查询:

ALTER TABLE mac_vod 
ADD INDEX idx_status_type (vod_status, type_id_1, type_id);

这将加速:

  • 过滤 vod_status = 1
  • 分组 type_id_1, type_id

例如以下 SQL 查询语句会因这个索引获得显著加速:
SELECT * FROM mac_vod
WHERE vod_status = 1 AND type_id_1 = 5 AND type_id = 12
ORDER BY vod_id DESC
LIMIT 30;

或者即使只用前两个字段(vod_status 和 type_id_1)也能利用索引:
SELECT * FROM mac_vod
WHERE vod_status = 1 AND type_id_1 = 5;

以后如果迁移数据库到其他服务器,这个索引会跟随 .sql 文件导出(前提是用 mysqldump 或 phpMyAdmin 导出结构 + 数据),不需要重复手动创建。

在某些情况下,如果不确定索引是否已存在(特别是从旧服务器导入数据后),可以先运行:
SHOW INDEX FROM mac_vod WHERE Key_name = 'idx_status_type';

如果看到返回结果中包含 vod_status, type_id_1, type_id 的字段组合,说明索引已经存在。

如果这条语句没有返回任何记录,就说明索引不存在,可以执行语句添加索引。

除此之外,要继续监测慢日志,如果出现其他高消耗查询也应该添加索引。

2、PHP-FPM 配置优化

1. pm.max_requests = 100

每个 PHP-FPM 子进程在处理 100 个请求后会自动重启。

优化作用:

  • 避免内存泄漏或长期运行的子进程 CPU 飙高;
  • 平滑回收导致高 CPU 占用的“老进程”;
  • 适合长期运行、偶发重负载的定时采集类业务。

这个参数是 PHP-FPM 性能稳定性的关键配置项之一。


2. rlimit_files = 10240

每个子进程允许打开的最大文件数(默认较小,容易触发 502 或阻塞)。

优化作用:

  • 减少 Too many open files 错误;
  • 提升并发能力、尤其是多任务采集、缓存写入等场景;
  • 更适合 Redis、MySQL、文件句柄并存的模型。

优化以后mysql,php-fpm的 CPU 占用明显下降,偶尔有systemd 的高占用,很可能是被恶意 SSH 扫描攻击拖高的,可以使用Fail2ban来进行防护。


另外网站日志和systemd 日志数据也容易被忽视,日志文件过大也会导致查询就会消耗大量 CPU 和 IO

网站日志可用宝塔计划任务来处理

systemd 日志数据处理:

查看日志大小
journalctl --disk-usage
Archived and active journals take up 3.7G in the file system. 日志占用严重偏高
只保留最近1天日志
journalctl --vacuum-time=1d
或限制大小为 100MB
journalctl --vacuum-size=100M

永久限制日志占用空间
编辑配置:/etc/systemd/journald.conf
整个 systemd 的日志文件最多使用 200MB 磁盘空间
SystemMaxUse=200M
日志系统会始终为磁盘保留 100MB 可用空间
SystemKeepFree=100M
每个 .journal 文件最大不超过 50MB
SystemMaxFileSize=50M
最多保留 5 个日志文件
SystemMaxFiles=5

保存后重启日志服务
systemctl restart systemd-journald

最终优化效果