MySQL-事务中binLog和 redoLog怎么保证一致性?

1,883 阅读2分钟

“这是我参与更文挑战的第5天,活动详情查看: 更文挑战

前边一篇我们说了binLog是在MYSQL的server层记录的,redoLog和undoLog是在MYSQL引擎层记录的。问题是MYSQL怎么保证两个日志同时记录成功呢?

首先我们要知道如果binLog和redoLog不能同时记录成功,会有什么影响?

  1. binLog记录成功redoLog记录失败,我们知道binLog其中一个功能是做数据库间的主从同步的, 如果binLog记录成功后自然就会同步到从库中,此时如果主库宕机redoLog没有记录导致数据无法持久化。(redoLog是保证MYSQL事务中持久性的)

  2. binLog记录失败redoLog记录成功,将会导致主从数据不一致情况。

MYSQL为了解决以上两种情况提供了两段提交方式,两段提交分别为prepare阶段、commit阶段。

prepare阶段:

SQL执行成功后将生成事务ID(xid)写入redoLog、undoLog缓存中注意此时并没有落盘也就是说没有持久化。

commit阶段:

写binlog,调用write()将binlog内存日志数据写入文件系统缓存,再调用fsync()将binlog文件系统缓存日志数据永久写入磁盘。同时将redoLog、undoLog从缓存中刷入磁盘进行持久化。

既然是两段提交那么如果commit阶段宕机了呢?

这时候prepare阶段数据将会丢失,不会导致binLog和redoLog不一致情况。

那么如果commit阶段中binLog写入磁盘成功但是redoLog失败呢?

MYSQL再次启动的时候会将binLog中的事务ID取出来检查redoLog有没有落盘成功,如果没有会将数据进行再次落盘。

commit阶段为宕机为什么会导致redoLog数据丢失呢? 这里我们就要说一下redoLog落盘策略

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9CYXE1bFlwSXc3WE9ZN0V1d24xS0hjOFBXeGhrUjdaZTk3MXpJTlhWd3FwMHNrZW9Za21PUXBHQXRjSmpjcmZYYTFkaDl2eEJERUlvbVl3OVkxdGlidGcvNjQw.png

mysql将redoLog buffer 写入 redoLog file 的时机,可以通过 innodb_flush_log_at_trx_commit 参数配置,各参数值含义如下:

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9UZVlrNDc4VzM2Qkg2cjlZaWFIbWljb0ZVZWljUm1DQzZjaGdZcFRzUlU2d1FJcDQyUjBKQ1ZLY0RwVkNsUlFFVHN6TGxpYk5CTk82blpJV1dYQTQ3NWNpYmhnLzY0MA.png

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9CYXE1bFlwSXc3WE9ZN0V1d24xS0hjOFBXeGhrUjdaZVRpYWxCc0VtbVpaVlNpYUx5QVJBSnZYaWF6eG54UjRpY2hhbVBzVkxSNFBYNEJ5RTEwZ0RPYTVVM1EvNjQw.png