分布式事务
OceanBase 数据库使用两阶段提交协议来实现分布式事务,以分布式转账为例,假设服务器节点 A 上的账户 UA 向服务器节点 B 上的账户 UB 转账,则两阶段提交的步骤是:
第一阶段,即 prepare 阶段,节点 A 和节点 B 分别检查账户 UA 和 UB 的状态是否正常、账户 UA 的余额充足且可以转出(没有超限)、账户 UB 可以转入(没有被冻结),检查通过则锁定账户 UA 和 UB。
第二阶段,即 commit 阶段,如果在第一阶段账户 UA 和 UB 的 prepare 操作都成功,则通知节点 A 对账户 UA 的余额进行扣减和通知节点 B 对账户 UB 的余额进行添加,转账成功;否则通知节点 A 和节点 B 对相应账户的操作进行回滚,转账取消。
然而,如果两阶段事务执行期间,某个节点,如 A,发生了故障,则无从知道 A 对账户 UA 的操作的状况:账户 UA 的 prepare 可能没有完成、或者完成且成功、或者完成但失败,节点 A 可能很快恢复、也可能很长时间没有恢复或者永久损坏,甚至无法简单地判断节点 A 是否故障或故障后是否恢复(例如监控节点并不总是能确定被监控节点的状态,因为监控节点本身或其与被监控节点之间的通信可能异常),因此该分布式事务的执行结果是不确定的。
Paxos + 两阶段提交协议:
OceanBase 数据库将 Paxos 分布式一致性协议引入到两阶段提交,使得分布式事务具备自动容错能力。如上图所示,两阶段提交的每个参与者包含多个副本,副本之间通过 Paxos 协议实现高可用。当某个参与者节点发生故障时,通过 Paxos 协议可以很快(秒级)选举出另外一个副本代替原有参与者继续提供服务,并恢复原有参与者的状态,从而确定分布式事务的执行结果并继续推进两阶段提交协议的完成。
为了提升系统的分布式事务处理能力,降低延迟,OceanBase 数据库进一步改进了传统的两阶段提交协议,采用参与者即协调者的优化,让每个分布式事务的第一个参与者承担两阶段提交协议中协调者的工作。如上图所示,传统的两阶段提交协议包含独立的协调者,协调者维护分布式事务的状态,执行 prepare 和 commit 操作后应答客户端,且每一个操作之前都需要记录日志,用于协调者故障后恢复分布式事务的状态,一次两阶段提交的延迟相当于 2 次 RPC 和 4 次写日志操作。OceanBase 数据库采用协调者无状态设计,协调者不再维护分布式事务的状态,而是在宕机恢复时,通过所有参与者的局部状态动态构造分布式事务的全局状态。这种方式避免了协调者写日志,一次两阶段提交的延迟降低到 1 次 RPC 和 1 次写日志操作。