首页 > 数据库 > 数据库开发技术 > 并发访问控制(2)-分布式事务处理
注释:如下所提及的文献,请按照索引号对应参考《分布式数据库原理、架构与实践》一书的引用参考。


什么是分布式事务?
维基百科中对分布式事务的定义[1]为:
A distributed transaction is a database transaction in which two or more network hosts are involved. Usually, hosts provide transactional resources, while the transaction manager is responsible for creating and managing a global transaction that encompasses all operations against such resources. Distributed transactions, as any other transactions, must have all four ACID (atomicity, consistency, isolation, durability) properties, where atomicity guarantees all-or-nothing outcomes for the unit of work (operations bundle).
上述定义翻译过来就是:分布式事务是涉及两个或多个网络主机的数据库事务。通常主机提供事务资源,而事务管理器负责创建和管理一个全局事务,该全局事务包含针对这些资源的所有操作。分布式事务与任何其他事务一样,必须具有具备ACID特性,其中原子性保证了工作单元(操作包)得到所有结果或者得不到任何结果。
分布式事务以分布式系统为物理基础,完成了事务处理的语义要求,即在分布式系统上满足ACID特性。所以分布式数据库的分布式事务处理,同样要遵循单机数据库系统下的事务相关理论,确保每个事务符合ACID的要求,采用分布式的并发访问控制技术来处理分布式系统下的数据异常现象。
[1]分布式事务的定义更多相关信息可参考:https://en.wikipedia.org/wiki/Distributed_transaction

事务处理策略
分布式事务处理,应遵循单机事务处理的策略:
q乐观并发控制策略:如分布式数据库Percolator、CockroachDB的事务模型实现就是乐观并发控制策略。
q悲观并发控制策略:如分布式数据库OceanBase、Spanner的事务模型遵循的就是悲观并发控制策略。
q混合机制:如分布式数据库TDSQL的事务模型的实现采用的就是在乐观并发控制策略中嵌入悲观并发控制策略。
与单机事务处理常采用悲观并发控制策略不同,常见的分布式数据库工程实现中,分布式事务处理策略不再局限于悲观并发控制策略,乐观并发控制策略和混合策略被采纳得更多。在分布式系统下采取哪种事务处理策略,是一个值得深入研究的课题,这和后续章节描述的事务处理架构联系密切。
混合机制是在一个系统内部,实现乐观和悲观并发控制策略的有机融合,这种融合把相关算法各自的优点融合在一起,以互补的形式消除各自的缺点。这种分布式并发访问控制技术被多个产品选用,尤其是工程界的TDSQL。
另外,《分布式数据库原理、架构与实践》一书的4.5.6节讨论的学术界正在研究的“自适应并发访问控制算法(Adaptive Concurrency Control Algorithm)”也是一种乐观和悲观并发控制策略结合的方式,这种方式可在同一个系统中实现多种并发访问控制算法,这些算法之间可根据事务负载进行切换。这种技术尚没有工程化的实现。

分布式事务处理架构
早期的研究,集中采取悲观并发控制策略实现分布式并发访问控制。基于封锁的分布式并发访问控制方法,使得所有的事务都要经过一个全局的事务管理器进行集中式处理,比如Postgres-XC由一个GTM(Global Transaction Manager,全局事务管理器)、多个Coordinator(协调器)、多个Datanode(数据节点)组成。GTM是Postgres-XC的核心组件,用于全局事务控制以及元组的可见性判断(GTM分配gxid、管理PGXC MVCC模块),在一个CLUSTER中只能有一个主的GTM,因为在这样的架构中存在单点GTM问题,所以严重影响了分布式数据库系统的性能。
另外封锁的分布式并发访问控制方法,还可能引发分布式死锁的问题。为了检测对资源高度并发访问的子事务的死锁,文献[38]提出基于图的检测算法,其中比较了两种不同的基于等待图(WFG)的死锁检测算法(中央控制和分布式死锁检测算法)的吞吐量,并评估了它们的性能。尽管死锁检测算法非常有效,但死锁检测过程对资源的消耗太大(在基于封锁机制的单机数据库中进行死锁检测,如InnoDB在并发冲突较高的情况下,消耗资源很大,严重拖累了系统的可用性;而基于封锁机制的分布式数据库进行死锁检测则对资源的消耗更大)。而对于分布式事务的子事务之间的死锁,即使能够检测出死锁,也很难解决死锁的问题。很多研究者将焦点集中在死锁检测上,他们认为在通用事务处理过程中,无法利用事务的先验知识来预防死锁。文献[39]提出基于Petri网络的死锁预防策略,利用动态的资源分配机制,开发基于Petri 网络模型的网络活跃状况或可达图的在线控制器。另外,在检测到死锁后,必须终止处于循环等待中的一个事务,以打破死锁。而在分布式数据库中,如果采用重试机制,但如采用的是不恰当的事务终止策略,可能会导致事务饥饿现象出现。文献[40]提出基于超时机制的概率分析模型,用于在分布式系统中检测全局死锁。但不管是基于超时机制还是基于等待图的死锁检测,都极大地影响着事务处理的效率,对此文献[41]进行了详细讨论。文献[42]把基于运行时等待图的必然死锁恢复运用到分布式死锁检测算法中,但这样的设计只能支持消息传递应用,而当网络中的进程和资源位置发生变化时,消息传递不再可靠,传送给特定接收者的探针消息会因为接收者位置改变而丢失,如果采取可靠协议的确认机制则会增加网络通信开销。
除了之上提及的封锁技术外,分布式事务处理技术还涉及很多其他类型的算法,这些算法都值得在分布式数据库事务处理技术中进行讨论。
如文献[43]指出,数据库系统的事务层和存储层可分离,事务层可不再关注物理上的数据结构和索引页,也不需要知道数据的物理布局对事务的影响。这种情况下,日志和并发协议都必须完全是逻辑层面的,只涉及记录键,而不涉及物理数据结构。另外,文献[43]还提出在分布式事务中消除2PC。
分布式事务并发访问控制方法CO算法[44,45,46,47,48,49,50,51],提出在分布式系统中,各个节点分别使用各自的事务处理机制,然后依赖CO和原子提交协议(2PC就是一种原子提交协议),即可在分布式数据库中达成全局可串行化。这为实现去中心化架构的分布式事务提供了理论基础。
另外《分布式数据库原理、架构与实践》一书的4.3节、4.4节和4.5等节提及的技术,也是分布式事务处理技术的核心技术。
总体来说,分布式事务型数据库的事务处理,存在两种架构:一是集中式的全局事务管理器,二是去中心化的事务处理架构。去中心化的事务处理架构渐成趋势,这得益于对前述多种技术的深入研究。

分布式事务的事务特性--原子性(Atomicity)
分布式事务需要衡量事务特性,即ACID四大特性。
原子性(Atomicity):每个事务为一个执行单位,事务整体要么成功要么失败。而一个事务由一到多个操作组成,每个操作要么是读操作要么是写操作。分布式事务同样需要遵守事务的原子性,事务的原子性和数据库系统的状态有关,也和同一份数据的副本数有关。
在数据库正常运行的情况下,事务可以成功提交或回滚,这时需要保证事务的原子性,成功提交时需要确保提交后的数据状态生效,回滚时需要确保被修改过的数据得到恢复。
若整个数据库出现宕机的情况,那么已经提交的事务不需要重新执行。如果预写日志中写了提交标志但事务尚未提交,那么节点重启时需要执行REDO日志以完成事务的提交,没有在预写日志中写有提交标志的事务则不需要执行REDO(或需要执行UNDO)日志。这要求分布式数据库中的每个节点都有节点级的预写日志。
分布式数据库的部分节点出现故障(如系统故障、介质故障、掉电、分区事件、通讯超时等),如果这些节点上的每份数据只有一份那么就意味着发生了单点故障,这时分布式数据库的可用性就降低了。为了提高可用性,每份数据通常都有多个副本。同一份数据的所有副本出现故障,则分布式数据库的可用性会降低。尽管这种情况出现的概率极低,但是依然有可能发生。若是同一份数据的部分副本出现故障,那么只要有半数以上的节点可用,就可对外正常提供服务,此时事务的读、写操作不受影响,原子性能够得到保障。所以分布式数据库中讨论的都是多副本的情况。此结论适用于下面将要讨论的一致性(事务一致性和分布式系统的一致性)问题。

分布式事务的事务特性--一致性(Consistency)
一致性(Consistency):数据库从一种合法的状态变迁为另外一种合法状态,数据发生变迁一定是有写操作存在,合法是指事务发生前和事务发生后的数据均符合“约束”的语义,而“约束”可以是数据库中定义的完整性约束、Check约束、唯一约束、触发器限定的约束等(甚至还可以是用户在数据间自定义的逻辑约束如同一个用户多个账户中现金余额的和大于零)。
对于同一个数据对象来说,因并发操作造成的各种读数据异常现象,在MVCC技术中造成的写偏序异常现象,在文献[21]等中有详尽分析,这里不再展开。
除写偏序异常外,分布式事务的一致性出现问题,一定是有并发写操作作用于同一个数据对象,也就是说必然有有多个事务同时发生。而分布式一致性中所涉及的单次读写操作作用于同一个数据对象,与分布式事务一致性有了交叉点——“操作同一个对象”。假设分布式一致性“所涉及的单次读写操作”在一个事务内,对具有强一致性(如线性一致性)的事务而言,按照事务的原子性和一致性语义,本事务内的写操作结果能够被本事务的读操作获取,一定不会发生分布式不一致,即一定能满足线性一致性。所以,对于分布式数据库系统而言,讨论严格可串行化时,对应的是两个事务第一个事务先执行写操作,第二个事务后执行读操作,此时,两个事务的两个操作间的关系就涉及了分布式一致性所讨论的内容。
对于分布式数据库,如果先写后读发生在一个会话内且是两个事务,则按照事务的语义和分布式数据库多副本的前提,后发生的读操作要么读取主副本,要么读取从副本且主备副本强同步,这样才能确保有读操作参与的分布式一致性满足严格可串行化。
对于分布式数据库,如果先写后读发生在两个会话内(必是两个事务),则按照事务的语义和分布式数据库多副本的前提,后发生的读操作要么读取主副本,要么读取从副本且主备副本强同步,且先写后读两个操作需要有排序的机制保证能识别出操作发生的物理顺序,这样才能确保有读操作参与的分布式一致性满足严格可串行化。
单机事务系统中,之所以不存在严格可串行化问题,是因为在单机上事务排序提交是依赖于同一个时钟源得到的时钟值,这个值是单调递增的(也有用一个计数器逻辑排序的方式),如基于TO算法时间戳,这保证了事务间调度单调有序。
上述只是讨论了有事务机制的情况下,分布式一致性如何被满足,对于事务的一致性,没有进行探讨。在分布式数据库中,事务的一致性可以从两个层面进行探讨,一是集中式事务处理机制,二是去中心化的事务处理机制。
对于集中式的分布式事务处理机制,分布式数据库中有一个全局的中央化的事务处理节点,所有并发的事务操作,都需要经过全局事务管理器进行分析和判断,并授予不同事务不同的物理标识,以解决事务之间的读写冲突,实现全局范围内的事务的提交和回滚操作,并实现全局的事务故障恢复和各个节点物理恢复时事务状态的还原。全局事务管理器存在单点可用性风险和性能瓶颈。在此种机制下,事务的写操作通常依靠2PC确保写操作的原子性,而读操作的一致性通过全局事务管理器进行管理。对于其他的数据异常现象,在集中式的分布式事务处理机制下其处理技术类似于单机事务型数据库系统,本章对此不再展开(单机事务处理技术,可参加参考文献[19]、[20]、[21]、[67])。
对于去中心化的分布式事务处理机制,每个事务既可能只操作单拷贝(同一份数据多个副本)的数据也可能跨多个拷贝的数据进行写操作。在去中心化的分布式数据库事务处理机制中,需要区分写操作的一致性和读操作的一致性。如在去中心化的事务处理机制中,因为有新的事务不一致现象发生,所以事务一致性的考虑需要扩展全系统而不是局限在在单个节点上。
写偏序异常发生在基于快照(Snapshot)的MVCC机制中,如果分布式事务的并发访问控制技术基于MVCC,同样需要考虑分布式事务处理模型是集中式的还是去中心化式的(参加文献[12])。
题外话:最近在一个群里见到的一段对话(从对话中可见——在一些范围内对一致性理解的片面性与深深的误解)
甲:请问一下,把原有oltp数据库的所有insert操作,select操作,全放进内存数据库,应用改造为双写。技术上风险有哪些,有点担心数据一致性问题..
乙:一致性和事务问题。(把一致性和事务并列了,关系不明)
甲:嗯,内存数据库 or 持久化数据库 任何一边 写入出了问题,不知道是写入成功的做rollback 还是写入失败的做补偿。
乙:事务问题超级复杂,在dba层面常见就是锁的粒度较大小。在业务层面,可能就多表多业务(事务问题是复杂,复杂到现有理论不能解释很多问题。但是,在DBA层面不是只是锁的粒度问题,也不是多表多业务哎)
丙:为什么要这么做啊?需要强一致性只能2pc啊(2PC的用途不明,很多人都如此,谈及分布式事务只谈2PC,似乎2PC就是分布式事务,完全错误)
丁:为啥强一致性只能2pc?2pc解决强一致性吗?(问得好)
丙:这也没有什么更好的protocol了(晕...)
更多一致性相关内容,请参考:

分布式事务的事务特性--隔离性(Isolation)
隔离性(Isolation):隔离性用于确保有并发事务存在的情况下,本事务的操作不被其他并发事务操作影响而丧失一致性,直至事务完成。隔离性的实现依赖于具体的并发访问控制技术,如果采用封锁机制,则加锁和释放锁的阶段决定了不同隔离级别的实现;而采用MVCC技术因操作的是不同版本的对象,所以在事务结束前天然隔离了并发事务间的相互影响[1]。在ACID中,一致性是目标,原子性是操作实现的原则,隔离性是实现一致性目标的手段,所以具体的并发访问控制技术和“读已提交策略”实现了隔离性,换言之,影响了一致性。在分布式数据库中,如果不能确保隔离性,则一致性不能得到保障。
[1] 这句话表述得其实并不十分精确。对于传统的解决写写并发冲突的MVCC技术,读写操作之间是隔离的,写写操作存在冲突需要解决。对于依赖“write-snapshot isolation”实现的MVCC技术(文献[21]),则需要解决读写操作之间的冲突。

分布式事务的事务特性--持久性(Durability)
持久性(Durability):事务提交后,新的数据状态必须被长久保存。实现这一特性的机制是WAL(预写日志技术)。在分布式数据库中,每个存储节点都需要有自己的预写日志。另外,预写日志也被用来实现故障恢复、物理备份恢复等(暂忽略NVM对事务的影响)。另外,预写日志在价值和作用方面与传统单机数据库系统也可能有较大的不同,如AWS的Aurora(参加文献 [282])系统,秉承的是“Log is Database”(日志即数据库)的理念,利用WAL对计算层和存储层进行解耦,WAL在实现持久性方面发挥了更大的作用。
上面讨论了分布式数据库中事务ACID特性的实现方式,重点讨论了事务的一致性,并结合了分布式系统的一致性中的严格可串行化对一致性问题进行了探讨。



扫码加关注,知数行云,专业有深度
声明:本文禁止用于开发“任何软件程序,包括但不限于训练机器学习或人工智能(AI)系统”。
原文作者:那海蓝蓝知数行云;如有侵权,请联系管理员删除。