Seata:开源分布式事务
一、概述
Seata 是一款开源的分布式事务解决方案,旨在为微服务架构下的分布式系统提供高性能且简单易用的分布式事务管理服务。以下将从多个方面对 Seata 展开详细介绍。
二、核心概念
(一)全局事务
全局事务指跨越多个服务或资源的事务,Seata 负责协调这些事务的提交或回滚,确保所有参与的本地事务要么全部成功,要么全部失败。
(二)事务协调器(TC - Transaction Coordinator)
事务协调器是 Seata 的核心组件,负责维护全局事务的状态,接收事务管理器的请求,并协调资源管理器的事务操作。它作为全局事务的管理者,记录着每个全局事务的状态信息。
(三)事务管理器(TM - Transaction Manager)
事务管理器用于定义全局事务的边界,负责开启、提交或回滚全局事务。在业务代码中,可通过 TM 来启动和管理全局事务,例如在 Java 代码里使用注解或 API 来开启一个全局事务。
(四)资源管理器(RM - Resource Manager)
资源管理器负责管理本地事务和本地资源,如数据库连接等。RM 会将本地事务与全局事务关联起来,执行本地事务操作,并根据 TC 的指令进行提交或回滚。
三、工作模式
(一)AT 模式(Automatic Transaction)
1. 原理
基于支持本地 ACID 事务的关系型数据库,Seata 会自动生成回滚日志。在业务 SQL 执行前,Seata 会对要修改的数据进行快照保存,执行后记录修改后的数据。当全局事务需要回滚时,RM 会根据回滚日志将数据恢复到事务执行前的状态。
2. 优点
对业务代码的侵入性极低,开发者几乎无需对业务代码进行修改,只需使用 Seata 提供的数据源代理即可。
3. 缺点
需要数据库支持事务和保存快照,对于一些不支持事务的数据库或存储系统不适用。
(二)TCC 模式(Try - Confirm - Cancel)
1. 原理
将一个全局事务拆分为多个阶段,每个阶段由业务开发者自行实现。Try 阶段进行资源的检查和预留,Confirm 阶段对 Try 阶段预留的资源进行确认提交,Cancel 阶段则在事务失败时释放 Try 阶段预留的资源。
2. 优点
性能较高,因为在 Try 阶段可以提前进行资源预留,减少了真正提交事务时的阻塞时间。同时,它对数据库的依赖较小,适用于各种类型的资源。
3. 缺点
对业务代码的侵入性较高,需要开发者手动实现 Try、Confirm 和 Cancel 三个阶段的逻辑,开发成本相对较高。
(三)Saga 模式
1. 原理
将一个长事务分解为一系列短事务(子事务),每个子事务都有对应的补偿事务。当某个子事务失败时,会按照一定的顺序执行前面已执行子事务的补偿事务,以将系统状态恢复到事务开始之前的状态。
2. 优点
适用于长事务和最终一致性场景,对业务代码的侵入性较低,通过事件驱动的方式进行协调,具有较高的灵活性和可扩展性。
3. 缺点
事务的一致性是最终一致性,可能会存在一定的延迟,在某些对数据一致性要求极高的场景下不太适用。
(四)XA 模式
1. 原理
基于 XA 协议,使用两阶段提交协议来协调分布式事务。在准备阶段,RM 执行本地事务但不提交,向 TC 报告事务执行状态;在提交阶段,TC 根据所有 RM 的状态决定是提交还是回滚全局事务。
2. 优点
严格遵循 XA 协议,能够保证强一致性。
3. 缺点
性能较低,因为在两阶段提交过程中会存在长时间的资源锁定,可能会导致系统的并发性能下降。
四、RM 回滚机制
在 Seata 框架中,当 RM(资源管理器)进行回滚操作时,本地数据库被更改的数据是通过 RM 内记录的回滚日志在本地执行对修改内容的覆盖,而非依赖本地数据库自身的回滚机制,具体解释如下:
(一)回滚日志的作用
- 记录数据修改信息:在事务执行的第一阶段(Prepare 阶段),RM 会在执行本地事务的业务 SQL 操作时,对要修改的数据进行快照保存,并生成回滚日志。这些日志详细记录了事务执行过程中对数据库的修改操作,包括操作类型(如
INSERT
、UPDATE
、DELETE
)、操作的数据行以及相关的字段值等。以 MySQL 为例,Seata 会将回滚日志记录在undo_log
表中。 - 提供回滚依据:当 TC(事务协调器)向 RM 发送全局回滚请求时,RM 会根据这些回滚日志来恢复数据库中的数据。由于回滚日志包含了数据修改前的状态信息,RM 可以利用这些信息将数据库中的数据恢复到事务执行前的状态。
(二)具体回滚过程
- 解析回滚日志:RM 接收到 TC 的回滚请求后,首先会从本地数据库中读取之前记录的回滚日志。这些日志以特定的格式存储,RM 会对其进行解析,提取出数据修改前的状态信息。
- 生成反向 SQL 语句:根据回滚日志中的信息,RM 会生成反向的 SQL 语句。例如,如果原始操作是
UPDATE
语句,将某条记录的字段值从A
修改为B
,那么回滚时 RM 会生成一条反向的UPDATE
语句,将该字段值从B
改回A
。 - 执行反向 SQL 操作:RM 会在本地数据库中执行生成的反向 SQL 语句,将数据库中的数据恢复到事务执行前的状态。通过这种方式,实现了对已修改数据的覆盖,完成了数据的回滚操作。
(三)不依赖本地数据库回滚机制的原因
- 跨数据库兼容性:Seata 要支持多种不同类型的数据库,不同数据库的本地事务回滚机制可能存在差异。通过使用自己的回滚日志,Seata 可以实现统一的回滚逻辑,确保在不同数据库上都能正常工作。
- 分布式事务一致性:在分布式环境中,本地数据库的回滚机制只能保证单个数据库内部的事务一致性,无法满足分布式事务的一致性要求。Seata 通过回滚日志和全局事务协调,能够确保所有参与分布式事务的数据库都能正确回滚,保证了整个分布式事务的原子性。
五、应用场景
(一)电商系统
在电商系统中,一个订单的创建可能涉及到多个服务,如订单服务、库存服务、支付服务等。使用 Seata 可以确保这些服务之间的事务一致性,避免出现订单创建成功但库存未扣减或支付失败但订单已生成的情况。
(二)金融系统
金融系统对数据的一致性和准确性要求极高,例如转账业务需要确保转出账户和转入账户的资金变动一致。Seata 可以帮助实现这种分布式事务的一致性,保障金融交易的安全可靠。
(三)物流系统
在物流系统中,货物的发货、运输、签收等环节可能涉及多个不同的服务和数据库。通过 Seata 可以保证这些环节的事务一致性,确保货物信息的准确和完整。
六、优缺点
(一)优点
- 高性能:Seata 采用了多种优化策略,如 AT 模式的自动回滚日志和并发控制机制,TCC 模式的资源预留和异步处理等,能够在保证事务一致性的前提下,提高系统的并发性能。
- 简单易用:提供了简单的 API 和注解,对业务代码的侵入性较低,开发者可以很容易地集成 Seata 到现有的项目中。
- 丰富的模式支持:支持多种分布式事务模式,开发者可以根据不同的业务场景选择合适的模式,满足多样化的业务需求。
- 开源社区支持:Seata 是开源项目,拥有活跃的开源社区,开发者可以得到及时的技术支持和更新。
(二)缺点
- 部分模式实现复杂:如 TCC 模式需要开发者手动实现 Try、Confirm 和 Cancel 三个阶段的逻辑,增加了开发的复杂度和成本。
- 一致性问题:Saga 模式实现的是最终一致性,可能会存在一定的一致性延迟,在对数据一致性要求极高的场景下需要谨慎使用。
- 依赖网络和协调器:Seata 的正常运行依赖于网络的稳定性和事务协调器的可靠性,如果网络出现故障或协调器崩溃,可能会影响分布式事务的正常执行。
七、Seata 实现的 2PC(两阶段提交)与传统 2PC 的区别
(一)协议实现层面
1. 通信复杂度
- 传统 2PC:协调者需要与每个参与者进行多次通信。在准备阶段,协调者向所有参与者发送准备请求,然后等待每个参与者的响应;在提交阶段,又要向所有参与者发送提交或回滚指令。这种频繁的通信增加了网络开销和延迟,尤其是在参与者数量较多时,通信复杂度会显著提高。
- Seata 实现的 2PC:Seata 对通信流程进行了优化。它引入了事务协调器(TC)、事务管理器(TM)和资源管理器(RM)等组件,通过组件之间的协作减少了不必要的通信。例如,RM 可以批量处理事务请求,减少与 TC 的交互次数,从而降低了通信复杂度。
2. 参与者自主性
- 传统 2PC:参与者相对被动,主要按照协调者的指令执行操作,缺乏一定的自主性。参与者在整个过程中主要是等待协调者的消息,并根据消息进行相应的准备、提交或回滚操作。
- Seata 实现的 2PC:Seata 的 RM 具有一定的自主性。RM 可以在本地对事务进行一定的预处理,如 AT 模式下自动生成回滚日志,而不需要完全依赖协调者的指令。这种自主性提高了系统的灵活性和可扩展性。
(二)性能方面
1. 资源锁定时间
- 传统 2PC:在准备阶段,参与者需要对相关资源进行锁定,直到协调者发送提交或回滚指令。在这个过程中,资源会被长时间锁定,可能导致其他事务的阻塞,降低了系统的并发性能。
- Seata 实现的 2PC:以 AT 模式为例,Seata 通过自动生成回滚日志的方式,减少了资源锁定的时间。在业务 SQL 执行前,Seata 对数据进行快照保存,执行后记录修改后的数据,而不是在整个 2PC 过程中一直锁定资源。这样可以提高系统的并发性能,减少资源竞争。
2. 故障恢复能力
- 传统 2PC:传统 2PC 在故障恢复方面相对较弱。如果协调者在发送提交指令后崩溃,部分参与者可能已经提交了事务,而其他参与者可能还在等待指令,这就会导致数据不一致的问题。而且,恢复过程通常比较复杂,需要人工干预。
- Seata 实现的 2PC:Seata 具有较强的故障恢复能力。当出现故障时,Seata 可以根据回滚日志和事务状态信息进行自动恢复。例如,在 AT 模式下,如果 RM 发现事务需要回滚,会根据之前记录的回滚日志将数据恢复到事务执行前的状态,保证数据的一致性。
(三)业务侵入性
1. 代码修改程度
- 传统 2PC:传统 2PC 对业务代码的侵入性较大,开发者需要在业务代码中手动实现准备、提交和回滚等逻辑,这增加了开发的复杂度和工作量。
- Seata 实现的 2PC:Seata 的不同模式对业务代码的侵入性不同。以 AT 模式为例,它对业务代码的侵入性极低,开发者几乎不需要对业务代码进行修改,只需要使用 Seata 提供的数据源代理即可。而 TCC 模式虽然需要开发者手动实现 Try、Confirm 和 Cancel 方法,但也提供了清晰的接口和规范,相对传统 2PC 来说,开发和维护更加方便。
(四)应用场景适应性
1. 场景多样性
- 传统 2PC:传统 2PC 主要适用于对数据一致性要求极高、参与者数量相对较少且网络环境较为稳定的场景。由于其性能和故障恢复能力的限制,在复杂的分布式系统中应用可能会遇到一些问题。
- Seata 实现的 2PC:Seata 提供了多种模式,如 AT、TCC、Saga 和 XA 模式,适用于不同的业务场景。例如,AT 模式适用于对业务代码改动要求小、数据库支持事务的场景;TCC 模式适用于对性能要求较高、业务逻辑复杂的场景;Saga 模式适用于长事务和最终一致性场景。这种多样性使得 Seata 能够更好地适应不同的分布式系统需求。