十三、优化案例——刷盘
之前提到过一种导致数据库性能抖动的异常,是由于系统 RAID 磁盘阵列的蓄电池定时充放电,导致 IO 不经过缓存直接写磁盘造成一段时间内数据库性能急剧下降。还有一种情况就是在高并发写的同时查询大量数据导致的性能抖动。
刷盘
如果要修改某条数据,首先要做的是从磁盘加载数据页到 Buffer pool 中 free 链表中的缓存页,然后这个缓存页移出 free 链表,加入 LRU 链表,修改后加入 flush 链表。同时在修改数据行前会写入 undo log 日志文件,然后修改数据行,再写 redo log 到 redo log buffer 中。等到事务提交时,会根据策略把 redo log 所在的 redo log block 顺序刷入磁盘。
然后在缓存页不足时或者后台定时线程会把 LRU 冷链尾部的缓存页刷入磁盘,也就是说这时缓存页刷盘有两个时机,一个是定时线程会把所有的 flush 链表中的缓存页刷入磁盘,另一个是缓存页不足时,会把 LRU 冷链尾部的缓存页刷入磁盘。
实际上还有另外一个刷盘时机,就是 redo log 覆写磁盘文件时,会判断第一个日志中 redo log 对应的缓存页是否刷入磁盘,因为缓存页没有刷入磁盘,而 redo log 一旦被覆写,就会导致这一部分数据在数据库宕机后无法恢复,所以这时会把那些缓存页强行刷入磁盘。在这种日志写满的情况下,会导致数据库无法处理任何更新请求,因为更新需要写日志啊。并且缓存页刷盘是一种随机写,本身就效率低下,所以才会导致数据库有时更新数据特费时间。

参数优化
经过分析后,导致性能抖动可能有两个原因:一个是,可能 Buffer pool 缓存页满了,然后此时要查询大量数据,会导致大量缓存页刷盘,才会使查询异常缓慢。再一个就是,大量的修改操作,导致 redo log 日志文件已满,需要覆写 redo log 文件,此时会导致缓存页大量刷盘。
所以说实际上都是由于瞬时大批量刷盘导致的性能抖动,要解决这个问题,一个是降低刷盘频率,再就是提升刷盘速度。要降低刷盘频率,这个问题只能是给 buffer pool 分配更大的内存空间,让 buffer pool 不那么快就满了。然后刷盘速度,可以通过调整 MySQL 参数来实现。
innodb_io_capacity:表示 MySQL 采用多大的 IO 速率去刷盘。由于刷盘是随机写,所以 SSD 固态硬盘的刷盘性能比机械硬盘的性能高了不止一点半点。这个参数实际上也就是调整为硬盘的 IOPS 就行了,以达到硬盘的最高性能。默认为 200
innodb_max_dirty_pages_pct:这个参数是 Buffer pool 脏页的比例,默认为 75%,同时也会参考 redo log 日志来调整。超过这个比例会触发刷盘。
innodb_flush_neighbors:flush 缓存页刷盘时会把临近的缓存页也会刷盘,为了加快刷盘速率,通常把这个参数设置为0
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· DeepSeek “源神”启动!「GitHub 热点速览」
· 上周热点回顾(2.17-2.23)