MySQL ACID
本文所有内容仅仅是对MySQL官方文档稍作整理,增加一些作者自己的理解。
随着业务数据和任务需求的增长,可靠性成了MySQL数据库的重要诉求(Redis早期仅有单句的增删改查,事务是随着业务需求变得复杂才增加的)。ACID正是实现MySQL可靠性的设计原则。
下文以InnoDB存储引擎为例简述了MySQL中如何体现ACID设计原则。
A(原子性), C(一致性), D(持久化)事实上都基于系统崩溃或者断电等导致数据库突然不可用的情况来考虑。I(隔离性)考虑并发情况下事务应当访问到何种数据。
A: atomicity
原子性,一个事务(包括单句增删改查操作)要么完成,要么失败,不存在修改一半的情况。这点通过事务的提交机制和回滚机制来保证。其中undolog起到了关键性作用,它记录了每条命令相反的命令,如果事务未提交完成遇到了失败,下次数据库重启时调用undolog回滚部分完成的事务。
C: consistency.
一致性。一致性的概念与下文中持久化关联非常紧密。官方文档中说明MySQL一致性体现在双写缓存和灾难恢复机制,而二者实际上也可以体现在持久化的原则中。持久化与一致性可以理解为因果关系,因为在机器正常运行的时候做了持久化的工作,才能在宕机之后根据持久化的文件(doublewrite buffer, redolog等)对数据库表空间(实际数据存储的地方)进行修复,以达到与宕机前数据库状态的一致性。
一致性只是一个设计原则,并不是数据库的某种机制,同样持久化也只是设计原则,而具体的机制如doublewrite buffer, redolog 被宕机这个时间点分成了两部分,宕机之前体现了持久化,宕机之后用作灾难恢复机制体现了一致性。因此也可以任务一致性和持久性并不是平行的设计原则,持久化保证了一致性。
实际上可以认为A,I,D三者共同保证了一致性。其中,原子性保证了数据库从一个状态转移到另一个状态,可能成功,可能失败,操作的结果与我们预期是一致的,隔离性保证了多个操作的顺序不影响数据库的最终状态,也就是无论事务操作的顺序如何,最终状态都是一致的,持久性保证了在宕机这段时间前后,数据库的状态一致。
I: isolation.
隔离性。四种隔离级别以及底层的InnoDB锁保证了MySQL事务之间可以做到某种级别的不干扰。
D: durability.
持久性。持久化是将内存中的MySQL页刷盘到磁盘中存储起来。
如果不做持久化处理,宕机后内存中的已经修改的MySQL页都将丢失。redolog 记录了对每个页的哪些偏移位置处做了何种修改。因此每次提交操作都写入redolog可以最大程度的保证数据的完整性,即使是没有提交的事务也可以恢复,因为redolog在每次操作的时候都会刷盘(因为redolog是连续存储的,所以刷盘影响不大)。
如果内存中的MySQL页往磁盘中写入一半的时候宕机了,则某些页可能写入错误,而重启的时候无法发现。redolog在刷盘的时候不存在此问题,因为每条redolog只占一个WORD,可以保证传输的原子性(UPS等备用电源机制可以保证即使断电也可以保证CPU指令的原子性)。doublewrite buffer解决了页部分写入的错误,具体实现也非常简单,首先将内存中数据页写入磁盘中的double write缓存,在这第一个写过程中即使宕机也不影响原始数据库的数据,然后再将doublewritebuffer内容写入到真正的表空间,在第二个写过程中即使宕机,因为doublewrite buffer是在磁盘上的且完整的,只需要重写一遍就可以了。