上一篇我们简单学习了事务ACID中的D持久性,这一篇我们看一下ACID中的A原子性。
基本流程
我们先看一下上一篇提到的客户端提交的事务是如何处理的:
当客户端提交事务后,innodb是先在内存提交事务,然后再通过异步刷盘的方式将内存的事务数据写入数据表物理存储磁盘。
存在问题
innodb一个page页默认是16KB,而linux系统一个page默认是4KB,如果要将innodb一个page页写入磁盘,至少需要4次I/0,如果在执行过程中,由于某种原因程序宕机了,只写入了8KB数据,这个时候就页就损坏了。
因为我们有redo log,那我们是不是可以通过redo log来恢复数据乃?
答案是不能!
redo log是Physiological Logging,里面只记录了对page页的逻辑修改,并不知道哪个地方损坏了。
所以就有了double write来保证数据能正确罗盘。
double write
double write双写是增加了一个double write buffer,默认有两个区,每个区1MB,即16KB*64。
- 先将数据copy到double write buffer
- 优先将double write buffer中的数据写入共享表空间物理存储(顺序写)
- 当共享表空间物理存储写入成功后,将double write buffer中的数据写入数据库表梳理存储磁盘(离散写)
通过流程我们可以看到,共享表空间物理存储其实也是file文件,只是因为是顺序写,性能非常高,速度非常快。共享表空间相当于就是一个文件备份,只有当出现宕机的时候,就从这个共享表空间进行恢复。
这样就最大化保证了数据刷盘的原子性。
但是如果我们在第3步中写了一般数据宕机了乃?
这个时候因为共享表空间已经有一份数据备份了,恢复的时候就直接从共享表空间进行恢复就可以了。而redo log有自己的恢复策略,两边并不受影响。
衍生的问题
当然,中间增加了double write buffer,并且还要优先写入共享表空间,只要存在写入,就存在sfync操作。就存在更多的性能开销。
但是由于顺序写性能非常高,相对于离散写,开销是非常低的。
像这种在数据完整性和性能之间做一个平衡,是软件架构中常见的策略。
最后
redo log也是写文件,那么他就不存在这样的磁盘写入问题吗?
答案是不存在,因为redo log的最小单位就是512字节,就不存在数据损坏。而且redo 也是循环顺序写,不存在这样的问题。
参考
- 《软件架构设计:大型网站技术架构和融合之道》
- 为什么数据不会丢,InnoDB的Double Write,你必须知道
- InnoDB关键特性之double write