1. 问题现象与初步排查
某客户生产环境数据库系统节点1出现CPU使用率持续高于90%的告警,持续时间超过2小时。作为DBA团队,我们首先通过监控系统确认了以下关键指标:
- CPU使用率:平均92%,峰值达到98%
- 负载平均值(Load Average):15分钟负载达到8.3(服务器为8核)
- 主要消耗来自用户态(user)进程,占比约85%
通过top命令实时观察,发现一个mysqld进程持续占用CPU超过700%(8核服务器满核为800%)。这明显异常,因为正常情况下该业务库的MySQL CPU使用率通常在30-50%之间波动。
注意:在Linux系统中,top命令显示的CPU百分比是相对于单个核心的。例如800%表示进程使用了全部8个核心。
2. 深入诊断与分析流程
2.1 数据库层面检查
首先使用MySQL自带的诊断工具进行排查:
-- 查看当前运行的所有线程 SHOW FULL PROCESSLIST; -- 查看性能模式中的事件统计 SELECT * FROM performance_schema.events_statements_summary_by_digest ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;发现一个高频执行的查询:
SELECT * FROM order_details WHERE user_id = ? AND status = 'pending' ORDER BY create_time DESC LIMIT 100;该查询平均执行时间达到1.2秒,且每分钟执行超过200次。通过EXPLAIN分析发现:
- 使用了全表扫描(type=ALL)
- 扫描行数:约120万行
- 返回行数:通常0-5行
2.2 系统层面分析
使用perf工具采集CPU使用热点:
perf top -p $(pgrep mysqld)输出显示CPU时间主要消耗在:
- 55.3% myisam_key_read
- 22.1% myisam_scan
- 12.7% malloc_consolidate
这表明存在严重的索引缺失问题和内存分配碎片化。
3. 问题根源定位
3.1 索引缺失分析
检查order_details表结构:
CREATE TABLE `order_details` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) DEFAULT NULL, `status` varchar(20) DEFAULT NULL, `create_time` datetime DEFAULT NULL, -- 其他字段... PRIMARY KEY (`id`), KEY `idx_create_time` (`create_time`) ) ENGINE=MyISAM;问题点:
- 查询条件中的user_id和status字段没有联合索引
- ORDER BY create_time与现有单列索引不匹配
- MyISAM引擎在高并发下有严重的表锁问题
3.2 查询模式变化
与开发团队沟通后了解到:
- 最近上线了新功能"用户待处理订单列表"
- 该功能会频繁刷新用户界面,导致上述查询激增
- 测试环境数据量小(约1万行),未发现性能问题
4. 解决方案与实施
4.1 紧急处理措施
- 添加临时索引缓解问题:
ALTER TABLE order_details ADD INDEX idx_user_status (user_id, status);- 优化查询语句:
SELECT * FROM order_details FORCE INDEX(idx_user_status) WHERE user_id = ? AND status = 'pending' ORDER BY create_time DESC LIMIT 100;- 调整MySQL配置:
[mysqld] table_open_cache = 4000 thread_cache_size = 32 key_buffer_size = 2G4.2 长期优化方案
- 存储引擎迁移:
ALTER TABLE order_details ENGINE=InnoDB;- 重建更合理的索引:
ALTER TABLE order_details ADD INDEX idx_user_status_time (user_id, status, create_time);- 应用层优化:
- 实现查询结果缓存(TTL 30秒)
- 限制刷新频率(前端防抖处理)
- 改为分页查询(LIMIT 20)
5. 验证与监控
5.1 效果验证
优化后指标对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| CPU使用率 | 92% | 45% |
| 查询响应时间 | 1200ms | 35ms |
| QPS | 200 | 20 |
5.2 监控增强
新增监控项:
- 慢查询日志监控(>500ms)
- 索引命中率监控
- 表扫描比例监控
配置报警规则:
- CPU持续>70%超过10分钟
- 同一SQL出现3次以上慢查询
- 索引命中率<95%
6. 经验总结与最佳实践
- 索引设计原则:
- 遵循最左前缀匹配原则
- 区分度高的列在前
- 避免过度索引(每个表不超过5个)
- MyISAM vs InnoDB选择:
- 读密集型且很少更新的表可考虑MyISAM
- 有写并发需求的必须使用InnoDB
- 事务需求必须使用InnoDB
- 上线前检查清单:
- 检查生产环境数据量与测试环境差异
- 分析新功能的所有SQL执行计划
- 评估可能的热点查询
- 应急处理流程:
- 先通过临时索引快速止血
- 再分析根本原因制定长期方案
- 最后完善监控防止复发
在实际运维中,我们发现80%的数据库CPU问题都源于索引缺失或不当。建议建立定期的索引审查机制,特别是在业务功能更新时,必须重新评估现有索引的适用性。