天天看点

MySQL怎么缓解写的压力?--- change buffer

想要优化写的速度,我们首先会想到什么?

随机IO转为顺序IO,单次写转为批次写。

缓存

常见的写逻辑优化,先写缓存,然后刷盘。

逻辑:

  • 如果页在内存中,直接修改。如果不在,读到内存,再修改。
  • 定期刷盘。

数据一致性

如果命中了缓存,读到的是准确的。内存淘汰的时候,刷盘了,再读磁盘的时候数据也是准确的。

问题

这样有两个问题:

  • 写多读少,就会导致命中缓存的概率比较低,每次都要先读到内存。
  • 如果崩溃了,内存的数据就丢了。

redolog

Innodb建立了redolog,即预写日志。写内存不变,添加了一步写redolog的步骤。刷盘的时候就把日志清掉。如果崩溃了,就从日志读取。

WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘。

redolog里面存的是结果值。也就是将change buffer同步到日志了。(binlog写的是流水日志)

这样就转化成了一次读磁盘,一次写内存操作和一次追加日志写的操作,都挺快。

change buffer

还有个问题就是写必须先读。

我们将更新的数据存到change buffer中,有人读则将读到的数据和change buffer中的数据一起返回。刷盘的时候将数据marge后刷盘。

这样就优化成了一次写内存+一次日志追加写。

但是要注意:

不支持唯一索引页。为什么?我不读盘怎么知道你有没有冲突呢?

什么时候刷盘?

  • 系统内存满了。
  • MySQL比较闲
  • 正常关闭

这些都比较好理解。

还有个下面的几种:

redolog写满了。

注意redolog不是无限写的,而是一个圈。

MySQL怎么缓解写的压力?--- change buffer
  • write pos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。
  • checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
  • write pos和checkpoint之间的是还空着的部分,可以用来记录新的操作。
  • 如果write pos追上checkpoint,表示满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把checkpoint推进一下。

定期刷新脏页或者LRU淘汰脏页

内存和磁盘数据一致的,称为干净页;反正,称为脏页。将内存数据写入磁盘,则便一致,称为刷脏页。

两种坑:

  • 某个查询需要刷新过多脏页,则很慢。
  • redolog写满,所有更新都会卡住。

那么,怎么提高刷脏页的效率?

  • 正确地设置innodb_io_capacity参数,判断写盘速度。
  • 脏页比例,innodb_max_dirty_pages_pct。
MySQL怎么缓解写的压力?--- change buffer

在准备刷一个脏页的时候,如果这个数据页旁 边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且这个把“邻居”拖下水的逻辑还 可以继续蔓延。

innodb_flush_neighbors 参数,为0就是只刷自己。

疑惑

很多人可能会问,到底是从redolog刷到磁盘,还是从内存刷到磁盘。

回到redolog创建的原因,是为了异常崩溃的时候。

所以正常刷盘是从内存刷到磁盘,redolog满了也是从内存刷到磁盘然后清理redolog。异常崩溃呢?也是从redolog写到内存中,先恢复现场,再走正常流程。

结语

  • 如果有不对的地方欢迎指正。
  • 如果有不理解的地方欢迎指出我来加栗子。
  • 如果感觉OK可以点赞让更多人看到它。

相关阅读:

  • 学MySQL的第一座大山—索引
  • 学MySQL的第二座大山—锁,事务
  • 学习mysql的最后一座大山—表设计
  • MySQL为什么要用B+树?
  • MySQL怎么缓解读的压力的?—buffer pool
  • MySQL怎么缓解写的压力?— change buffer
  • MySQL架构概览