陆敬尚,Apache ShardingSphere Committer,SphereEx 基础设施研发工程师,热爱开源,热爱数据库技术,目前专注于 Apache ShardingSphere 事务模块的开发。
背景
随着业务的快速发展,数据的不断膨胀,流量负载的增加,业务系统遇到了强烈的挑战,对数据库系统可扩展性提出了强烈的诉求。Oracle、MySQL、SQL Server、PostgreSQL 传统单机数据库在线扩展上的问题日益凸显。为了解决扩展问题,出现了可水平扩展的分布式数据库,于是分布式事务问题成为了必须面对的问题。
在这种背景下,ShardingSphere 提供了一套分布式数据库增强计算引擎,通过可插拔架构构建基于数据库之上的生态系统,提供了分布式事务的能力。
事务介绍
事务语义
事务语义定义了四个特性:原子性(Atomicity)、持久性(Durability)、一致性(Consistency)、隔离性(Isolatation)。
原子性(Atomicity)
在分布式场景下,一个事务的操作可能分布在多个物理节点上,保证在多个节点上的操作都成功,或都不成功。
持久性(Durability)
事务提交后,即使断电,事务的操作也是有效的。
一致性(Consistency)
注意:不是 CAP 理论中 C,CAP 中的 C 指的是多副本之间的数据一致问题,这里是不同层次的抽象。
站在用户的角度,数据从一个状态,转移到另外一个状态,两个状态都满足一定的约束。比如:
银行账户数据,账户 A 有 500 元,账户 B 有 500 元,总额 1000,在一个事务中,执行完 A 和 B 的转账操作后,A 和 B 的账户总额还是 1000。
隔离性(Isolatation)
事务并发执行时,保证并发时数据的正确性。比如:两个事务同时修改一条数据,保证两个事务按一定顺序执行,使数据保持在一个正确的状态。
面临的挑战
分布式事务相对单机事务来说面临下面的挑战:
-
原子性,对于单机事务来说,使用 undo log 和 redo log 就可以保证全部提交或者全部回滚。而分布式事务涉及多个物理节点,每个节点情况是不同的,有的节点日志写成功,有的节点日志写不成功。
-
网络的不稳定,对于单机来说,通讯是稳定的,任何操作都可以得到回复,不论成功与失败。而分布式场景下,网络是不稳定的,有可能一个操作是得不到回复的,怎样保证分布式事务的可用性(异常事务的清理、恢复等)是一个问题。
-
并发控制,随着 MVCC 的出现,操作的可线性化(linearizable)成为了刚需。在单机数据库中,可以很容易地产生全局单调递增的事务号,在分布式场景中则不然。
解决方案
原子提交
针对原子性和网络不稳定问题,目前主流的解决方案是 2PC,2PC 定义了两个角色 TM(Transaction Manager)、RM(Resource Manager)。
在分布式场景下,一个事务的操作可能分布在多个节点上,整个事务分两个阶段。
-
第一阶段,RM 锁定相关资源并执行具体操作,返回成功与否给 TM。
-
第二阶段,TM 更具第一阶段 RM 返回的结果,如果全部成功,执行最后的提交操作(事务状态的更改,锁状态删除等),如果有失败的,则回滚。
说明:当然会有一些优化点,比如不涉及多节点的事务转化为一阶段提交等。
注意:两阶段提交协议只解决了提交的问题,要么提交成功,要么不成功,不存在部分成功的中间状态。和事务隔离级别没有必然关系。
并发控制
并发控制,就是保证并发执行的事务在某一种隔离级别上的执行策略。自从多版本控制(MVCC)出现,主流数据库基本抛弃了以前的两阶段锁模型。
并发控制本质是对数据读和写的并发的控制。并发控制的策略决定了隔离级别,并发控制要解决两个问题。
-
决定并发的粒度,比如 MySQL 有行锁(粒度为一行),表锁(粒度为一个表)等
-
三种并发场景的行为:
a. 读读并发,不需要特殊处理,因为不涉及数据的变更。
b. 写写并发,不能同时并发,否则会产生数据混乱。
c. 读写并发,性能优化主要在这里做,有多种并发控制机制,基本都选择了多版本并发控制(MVCC)。
MVCC 并发控制模型
现有主流实现方式有两种ÿ