传统的事务要求必须实现 ACID,分别是:
-
原子性
一个事务所包含的操作,要么全部完成,要么全部不完成。 -
一致性
在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这种一致性要求不仅指常见的数据库完整性约束(例如主键,外键,触发器,check等约束),有时还需要由用户应用程序来保证。 -
隔离性
数据库允许多个并发事务同时对其数据进行读写和修改,隔离性可以防止多个事务并发执行时,由于交叉执行而导致数据出现异常的情况。不同的隔离级别有着不同的保证。 -
持久性
事务结束后,对数据的修改是永久的,即便系统出现故障也不会丢失数据,这其实就是将数据写入非易失性存储。
分布式事务也需要遵循 ACID 四个基本属性,实际上,无论是分是不是系统还是单机系统,事务一致性和持久性的实现都没有太大的差别:
为了实现一致性,系统可以在事务的前后引入一些额外的读写操作,以保证数据符合完整性约束。
为了实现持久性,只需在客户端返回响应之前,确保将数据存储在非易失性存储设备即可,通常还会包括一些WAL或者其他日志文件。
可见,就一致性和持久性来说,分布式事务并不需要特殊的实现方式,基本与单机系统类似。
相比之下,原子性和隔离性在分布式系统中的实现就充满了挑战,它俩在分布式系统中的实现分别对应了原子提交和并发控制。
原子提交
在分布式系统中实现分布式事务,需要我们确保一个操作在一个节点的原子性,还要确保一个操作在多个节点的上原子性。比如 保证在所有节点的数据写操作,要么全部都执行,要么全部的都不执行。
这是通过原子提交协议来实现,原子提交协议也叫原子提交算法,原子提交协议必须满足以下3个特性:
-
协定性
所有进程都决议出同一个值,相当于所有进程要么一起提交事务,要么一起中止事务,不存在两个进程一个提交事务而另一个中止事务的情况。 -
有效性
如果所有进程都决定提交事务并且没有任何故障发生,那么最终整个系统将提交事务,只有一个进程决定中止事务,系统将中止事务。 -
终止性
终止性又分为弱终止条件和强终止条件:
弱终止条件是指:如果没有任何故障发生,那么所有进程最终都会做出决议(提交或者终止事务)。
强终止条件也称为非阻塞条件,是指:没有发生故障的进程最终会做出决议。
从这上面来看,原子提交协议实际上解决了分布式共识问题的一个子类,即对事务的提交或中止达成共识。常见的原子提交协议有:两阶段提交算法,三阶段提交算法,paxos提交算法等。
并发控制
除了原子性,分布式事务还需要实现隔离性。并发控制是一种隔离并发事务以保证数据正确性的机制,对于实现并发控制,分布式事务采取的方案和经典的方案并没有什么太大的差别。不同的并发控制机制用来实现不同的隔离级别,一般来说,可以将并发控制分为以下三类:
-
悲观并发控制(Pessimistic Concurrency Control,PCC)
这种方法通常涉及到锁,需要先获取数据的锁,如果一个事务持有了数据的锁,那么另一个事务就必须等待前一个事务结束并释放锁。该方法主要用来实现串行化的隔离。 -
乐观并发控制(Optimistic Concurrency Control,OCC)
这种方法基本思想是在事务执行时并不考虑存在其他事务读写该事务正在操作的数据,只管继续执行读写操作。在事务提交的时候,再检查是不是有其他并发事务引起了冲突,如果没有冲突,那么这次事务就算完成了,如果最后检查发现事务操作的数据被其他并发事务修改并造成了冲突,那么必须中止当前事务,并在稍后重试事务。 -
多版本并发控制(Multi-Version Concurrency Control,MCC)
这种方法对每个数据项保存多个版本的数据,并保证每个事务的读操作读取到比该事务早的最后一次提交的数据。
参考资料
1、《深入理解分布式系统》
网友评论