MySQL为什么有时候会抖动一下?

一、InnoDB 刷脏页(最常见原因)

现象

  • 监控可见磁盘 I/O 突增,TPS 短暂下降。
  • SHOW ENGINE INNODB STATUSBUFFER POOL AND MEMORYModified db pages 值较高。

原因

  • 脏页积累:内存中的脏页(修改后未刷盘的数据页)积累到阈值(默认 75%),触发后台刷盘。
  • Redo Log 切换:Redo Log 写满切换时强制刷脏页(Checkpoint 机制)。

解决方案

  1. 调整刷盘速度

    ini 复制代码
    innodb_io_capacity = 2000        # 根据磁盘性能设置(SSD 建议 2000~20000)
    innodb_max_dirty_pages_pct = 60  # 降低脏页比例阈值
  2. 优化 Redo Log

    ini 复制代码
    innodb_log_file_size = 4G        # 增大 Redo Log 文件(减少切换频率)
    innodb_log_files_in_group = 3    # 增加日志文件数量
  3. 监控脏页状态

    sql 复制代码
    SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';

二、日志系统(Redo Log/Binlog)压力

现象

  • 事务提交延迟,SHOW PROCESSLIST 显示大量事务处于 query end 状态。
  • 监控显示磁盘写入延迟高。

原因

  • Redo Log 刷盘策略innodb_flush_log_at_trx_commit=1 时每次提交同步刷盘,I/O 压力大。
  • Binlog 刷盘策略sync_binlog=1 导致每次提交同步刷 Binlog。

解决方案

  1. 平衡一致性与性能

    ini 复制代码
    innodb_flush_log_at_trx_commit = 2  # 提交时写 OS 缓存,每秒刷盘(牺牲少量持久性)
    sync_binlog = 1000                  # 每 1000 次提交刷一次 Binlog
  2. 使用高性能磁盘:SSD 提升日志写入速度。


三、查询性能突增

现象

  • CPU 使用率或锁等待时间突增。
  • 慢查询日志中突然出现复杂查询。

原因

  • 低效 SQL 突然执行:全表扫描、未命中索引的查询。
  • 锁竞争加剧:热点行更新导致锁等待。

解决方案

  1. 捕获慢查询

    ini 复制代码
    slow_query_log = ON
    long_query_time = 0.5
  2. 优化 SQL

    • 添加缺失索引。
    • 重写复杂查询,避免全表扫描。
  3. 减少锁冲突

    • 使用 innodb_autoinc_lock_mode=2(交错自增锁)。
    • 缩短事务长度,尽快提交。

四、内存不足或 Swap 触发

现象

  • 内存使用率接近 100%,vmstat 显示 si/so(Swap 换入换出)值高。
  • SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_wait%' 显示等待次数。

原因

  • Buffer Pool 不足:频繁从磁盘加载数据页。
  • 系统内存竞争:其他进程占用内存,触发 Swap。

解决方案

  1. 扩大 Buffer Pool

    ini 复制代码
    innodb_buffer_pool_size = 系统内存的 70%~80%
  2. 禁用 Swap

    bash 复制代码
    sysctl vm.swappiness=0
  3. 优化内存分配

    ini 复制代码
    innodb_buffer_pool_instances = 8  # 减少锁争用

五、后台维护任务

现象

  • 定期出现性能波动(如每天凌晨)。
  • SHOW PROCESSLIST 显示 OPTIMIZE TABLEANALYZE TABLE

原因

  • 统计信息更新ANALYZE TABLE 导致临时资源消耗。
  • 表优化操作OPTIMIZE TABLE 重建表文件。

解决方案

  1. 调整维护计划

    • 在业务低峰期执行 OPTIMIZEANALYZE
  2. 启用持久化统计信息

    ini 复制代码
    innodb_stats_persistent = ON
    innodb_stats_auto_recalc = ON

六、硬件或系统层问题

现象

  • 磁盘延迟高(iostat -x 显示 await 值突增)。
  • 网络波动(如云服务器网络带宽突增)。

解决方案

  1. 监控硬件指标
    • 磁盘健康度(SMART 状态)。
    • 网络带宽使用情况。
  2. 升级硬件
    • 更换 SSD 提升 I/O 能力。
    • 增加内存避免 Swap。

七、诊断工具与命令

  1. 实时状态分析

    bash 复制代码
    # 查看系统资源
    top
    iostat -x 1
    vmstat 1
    
    # 查看 InnoDB 状态
    SHOW ENGINE INNODB STATUS\G
  2. 历史趋势分析

    • 使用 Prometheus + Grafana 监控 MySQL 和系统指标。
    • 开启 Performance Schema 记录历史查询。

总结:按优先级排查

  1. 检查刷脏页 → 调整 innodb_io_capacity 和 Redo Log 配置。
  2. 优化日志刷盘策略 → 平衡 innodb_flush_log_at_trx_commitsync_binlog
  3. 捕获慢查询 → 优化 SQL 和索引。
  4. 检查内存压力 → 扩大 Buffer Pool,禁用 Swap。
  5. 排查硬件问题 → 监控磁盘和网络。
相关推荐
lovebugs22 分钟前
Java并发编程之Lock机制:更灵活的线程同步方案
后端·面试
Nicole Potter35 分钟前
内存泄漏出现的时机和原因,如何避免?
c++·游戏·面试·c#
liujingtech2 小时前
Android如何让属性动画更加优雅与生命周期绑定
面试
Huooya3 小时前
springboot的外部配置加载顺序
spring boot·面试·架构
钢板兽4 小时前
Java后端高频面经——Spring、SpringBoot、MyBatis
java·开发语言·spring boot·spring·面试·mybatis
钢板兽4 小时前
Java后端高频面经——JVM、Linux、Git、Docker
java·linux·jvm·git·后端·docker·面试
A仔不会笑4 小时前
MySQL面试篇——性能优化
java·数据库·mysql·面试·性能优化
uhakadotcom4 小时前
ClickHouse入门:快速掌握高性能数据分析
后端·面试·github
雷渊4 小时前
深入分析mysql中的binlog和redo log
java·后端·面试