数据库分布式事务简介

2024-09-21 database

分布式事务与传统的单机事务要复杂很多,由此衍生出来多种算法,这里简单介绍。

简介

当多节点参与时,除了要满足 ACID 特性之外,还有共识 (Consensus) 问题。

Atomic: 在网络、节点故障场景下如何保证
Consistency: 不会出现中间态
Isolation: 大延迟会不会导致持锁时间过长
Durability: 多副本
Consensus: 多副本能否表现的像一个副本

分布式事务实际使用时有两种场景:

  • 数据库层面,当单机无法满足时,拆分为多机对外提供服务,可以是类似 OceanBase、TiDB 这种分布式数据库,也可以是基于 XA 协议在 MySQL 上封装的代理层。
  • 微服务层面,某个服务被拆分到不同的服务器上,例如交易系统,需要同时调用订单、扣款、库存等服务,这一过程中如何保证业务整体的事务性。有很多 SDK 的相关实现,例如 SeataByteTCCTccTransactionEasyTransaction 等。

相比单机事务,分布式系统的事务处理要更加复杂,主要原因有:

  • 多节点,不同节点在事务执行的不同阶段可能会出现异常,例如 A 节点成功锁住资源,但是 B 节点加锁失败;A 节点事务提交成功,但是 B 节点在提交时宕机了;多个节点提交时,始终有某个节点失败。
  • 网络或者主机异常导致未收到响应,在 A 告诉 B 提交事务时超时,可能是 B 压根没有收到请求,也有可能是 B 已经处理完了,但是响应的报文丢失了。
  • 网络延迟,通常在单机上的简单实现在分布式场景下已经不再适用,例如事务 ID,需要同时保证唯一性,可能还需要保持递增。

2PC

也就是 Two Phase Commit, 2PC 两阶段提交,包含了两个角色,对应 A) 参与者 (Participant),管理本地资源,实现本地事务;B) 协调者 (Coordinator),管理分布式事务,协调各个参与者。

第一阶段中,协调者分配事务 ID 并持久化到磁盘,然后调用所有参与者执行事务;参与者开始执行事务,可能需要对资源加锁以及 Redo/Undo 日志落盘;如果参与者执行成功,则返回 Yes 否则返回 No 结果。

第二阶段中,分成了两种情况。

  • 所有参与者回复 Yes,事务准备成功,执行 Commit 操作 协调者写 Commit 日志并落盘,并向所有参与者发送 Commit 请求;参与者执行 Commit 操作,包括 Commit 日志落盘、释放资源,然后响应协调者;协调者接受到所有参与者完成消息后,事务提交成功。
  • 至少一个参与者回复 No,事务准备失败,执行 Abort 操作 协调者写 Abort 日志并落盘,并向所有参与者发送 Abort 请求;参与者执行 Rollback 操作,释放资源,然后响应协调者回滚完成;协调者接受到所有参与者完成消息后,取消事务。

看着很简单,关键是如何处理服务器宕机和网络超时等问题。其中有个原子,如果协调者已经提交事务,那么各个参与者就必须要提交,绝对不允许回滚。

TCC

最早由 2007 年 Pat Helland 在 Life beyond Distributed Transactions 提出,该模型中,事务参与者需要实现如下三个接口:

  • Try 参与者检查资源是否有效,预留资源。
  • Confirm 参与者提交资源。
  • Cancel 参与者执行回滚操作,恢复预留资源。

该模型没有在 Try 阶段加锁,性能要高于两阶段提交,不同事务可以并发执行。

Percolator

Google 会定期爬取页面并保存到索引中,通过 Percolator 系统处理大规模的增量数据,该系统是构建在 BigTable 之上的,提供了 Snapshot Isolation 语义。简言之,其基于 BigTable 的单行事务和全局授时服务器 TSO 实现了跨机多行的分布式事务。

TSO 的全称是 TiemStamp Oracle,虽然带了 Oracle 关键字,但并非指数据库,而是其原始含义,也就是神谕、神授的、不可质疑的。

总体来说,这是一个优化后的两阶段提交,最初源自 Large-scale Incremental Processing 这篇论文。

基本原理

在论文中定义了 5 列,实际核心的涉及到如下三列:

  • lock 保存未提交的锁信息。
  • write 提交信息,包含对应的时间戳。
  • data 真实的数据。

OMID

这是基于 Percolator 的改进。