news 2026/10/29 1:42:30

Seata 分库分表整合指南:ShardingSphere + AT 模式,5 步跑通跨库事务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Seata 分库分表整合指南:ShardingSphere + AT 模式,5 步跑通跨库事务

Seata 分库分表整合指南:ShardingSphere + AT 模式,5 步跑通跨库事务

【免费下载链接】incubator-seata:fire: Seata is an easy-to-use, high-performance, open source distributed transaction solution.项目地址: https://gitcode.com/gh_mirrors/in/incubator-seata

当业务数据用 ShardingSphere 按规则拆到多个物理库之后,一次"下单"可能同时要写订单库和库存库。问题边界很清楚:本地事务的提交/回滚只能作用于单个数据库连接,一旦跨库,先成功的写入无法跟随后失败的写入一起撤销。后果就是两个库之间出现中间状态——一边扣了库存,一边没有订单——而且这种不一致在网络抖动、应用宕机时会被放大。Seata 提供的分布式事务机制,正是为把这种跨库写入重新纳回"要么全成、要么全败"的约束而设计的,其中 AT 模式对分库分表场景的适配成本最低。

一、先选型:四种模式各自的适用边界

在动手之前,值得先把主流路线摆开对比。判断维度不是"谁更先进",而是三件事:一致性强度、对业务代码的侵入程度、以及性能代价。

  • 经典 2PC:由协调方持有一切参与方的行锁直到最后时刻。一致性最强,但所有参与方在等待期间无法做任何事,长事务下吞吐掉得很快。适合事务极短、参与方很少的内部批处理,不适合面向用户的在线链路。
  • TCC:业务方自行实现 Try(预留资源)/ Confirm(确认)/ Cancel(取消)三组接口,锁是业务自己做的"逻辑锁",不占用数据库行锁。性能最好、侵入性最大,三个方法都要处理幂等、悬挂、空回滚。适合交易核心链路且团队有充足人力。
  • Saga:把长流程拆成一串本地事务,每一步配一个补偿动作,靠状态机驱动前进与回退。它是"最终一致",中间状态对外可见。适合流程长、环节多(审批、物流流转这类)的场景。
  • AT(本文选型):对业务 SQL 无侵入,框架在每条 DML 前后自动记录数据快照,第一阶段随业务本地事务正常提交,第二阶段由协调者(Seata Server)统一裁决提交或回滚。代价是持有全局行锁的周期比本地事务略长,且依赖被操作表有主键。分库分表场景选它的理由很直接:ShardingSphere 负责路由,Seata 负责协调,两边都不需要改动业务 SQL,也不要求业务方重写补偿逻辑。

如果流程本身就很长(几十秒起步)或者步骤之间天然可补偿,优先考虑 Saga——Seata 内置了可视化状态机设计工具,可以图形化编排节点与补偿:

Seata 自带的 Saga 状态机设计器,服务任务的入参与补偿策略均可图形化配置

下文以 AT 模式为主线,结合 ShardingSphere 给出最短可运行的落地路径。

二、最短落地路径:从环境要求到验证

1. 环境要求

  • 数据库:MySQL 5.7 及以上(InnoDB,需要 binlog 支撑主从场景)
  • Seata Server:2.0.0 及以上版本,存储模式建议 db 模式,建表脚本在 script/server/db/mysql.sql,会创建global_table、branch_table、lock_table三张表
  • ShardingSphere:5.x 稳定版,配置好分库分表规则
  • 应用侧:Spring Boot +seata-spring-boot-starter(对应模块见 spring/seata-spring-boot-starter)

从源码构建 Server 的最短命令:

git clone https://gitcode.com/gh_mirrors/in/incubator-seata cd incubator-seata ./mvnw clean package -DskipTests sh distribution/server/target/seata-server-*/bin/seata-server.sh -p 8091 -h 127.0.0.1 -m db

2. 关键配置(最小可运行)

(a)每个物理分库都建 undo_log 表。这是最容易被漏掉的一步。分库分表之后"业务库"是 N 个物理实例,AT 模式回滚依赖每个库里的undo_log表,DDL 直接取仓库现成脚本 script/client/at/db/mysql.sql,对每一个物理分库各执行一次。注意undo_log本身不分片,它在每个分库中都是单表。

(b)数据源装配顺序。顺序必须固定:先用 ShardingSphere 规则构建ShardingSphereDataSource,再用 Seata 的DataSourceProxy包在它外面(见 rm-datasource/src/main/java/org/apache/seata/rm/datasource/DataSourceProxy.java)。用 starter 时这一步由自动装配完成,手动装配时不能反。

(c)应用侧最小 YAML:

seata: enabled: true application-id: order-service tx-service-group: my_tx_group service: vgroup-mapping: my_tx_group: default client: undo: log-table: undo_log

vgroup-mapping的含义是把tx-service-group映射到 Seata Server 的注册名,两个 key 必须对得上(绑定关系定义见 ServiceProperties.java)。本地直连测试时可改用grouplist直接写 Server 地址,跳过注册中心。

(d)业务代码加一个注解:

@GlobalTransactional(rollbackFor = Exception.class) public void createOrder(OrderDTO dto) { orderMapper.insert(dto.toOrder()); // 订单库(可能路由到分片 A) inventoryMapper.deduct(dto); // 库存库(可能路由到分片 B) }

ShardingSphere 路由照常工作:同一条 DML 被路由到哪个物理库,就在那个库的本地事务里执行并被 Seata 记录为一个分支。

3. 验证方法

  1. 正向:正常下单,确认订单与库存同时落库,且每个被写到的分库中undo_log有记录,全局事务结束后记录被清理。
  2. 反向:在扣减库存之后人为抛异常,重启/等待回滚完成,确认订单记录消失、库存恢复,两个分库状态一致。
  3. 并发:对同一热点行加压(示例量级:50~100 并发),确认不出现超卖,只出现部分请求因全局锁等待而超时重试。

4. 随路调优参数

不必单独搞调优阶段,下面几项在初版配置里一并给掉即可(key 名以 ConfigurationKeys.java 为准):

  • client.rm.reportRetryCount(默认 5 次):分支注册/结果上报失败的重试次数,网络不稳时先确认这一项
  • client.tm.commitRetryCount/client.tm.rollbackRetryCount:全局提交/回滚指令的重试
  • client.undo.retryCount:回滚时校验与恢复的重试
  • server.undo.logDeleteDays及 undo 压缩开关:控制undo_log的清理与体积

三、关键机制拆解:两个最容易被误解的点

AT 的回滚靠"存档",不靠"重放 SQL"

现象:全局回滚时,业务代码并没有被执行"反向",库存数字却能精确恢复。

机制:AT 的第一阶段并不是简单地执行业务 SQL。每条 UPDATE/DELETE 在执行前,框架会先读出受影响行的完整原值(before image),执行后再读出新值(after image),把两份快照连同xid、branch_id一起写入undo_log(表结构见上文脚本),然后让本地事务正常提交——注意是提交,不是挂起。回滚阶段由客户端读取undo_log,直接用 before image 拼 UPDATE 语句把行改回去;之后还会校验该行的当前值仍等于 after image,防止回滚期间有外部写入覆盖。

结论:第一阶段的"提交"是为了尽早释放数据库本地锁,回滚正确性完全押注在"before image 完整 + 回滚期间该行没被别人动过"这两个前提上。这也解释了为什么被操作表必须有主键——没有主键就无法精确定位受影响行,快照机制直接失效。

log_status 的"防御位":为什么回滚后还要防一笔晚到的写入

undo_log里有个log_status字段:0 表示正常,1 表示防御态(见 AbstractUndoLogManager.java 中对GlobalFinished状态的定义)。考虑一个时序:全局事务已回滚完毕,但某个慢分支迟到的事务才提交,此时它会往已回滚的数据上"补写"。框架的做法是在全局事务结束时给相关undo_log打上防御标记,迟到分支写快照前先检查该标记,发现全局事务已终结就拒绝插入、快速失败。

结论:AT 的一致性保证覆盖的是"分支在协调者裁决前完成注册"的场景;跨全局事务的并发冲突由lock_table中的全局行锁裁决——持有全局锁期间,其他事务对同一行的写操作会被挡住,读操作则不受全局锁影响。

分支事务如何被"裁决"

一条 SQL 走 Seata 代理连接时:RM 先向 TC 注册分支(拿到全局事务上下文)→ 本地执行 DML 并写快照 → 本地提交 → 向 TC 上报分支结果。TC 在收到所有分支的成功上报后进入全局提交(AT 模式下提交即"什么都不做",因为第一阶段已提交,异步清理即可);只要有一个分支最终失败,TC 向所有分支下发回滚指令,客户端按上文机制用 undo_log 恢复数据,失败分支会按重试策略反复尝试直到成功或放弃并进入人工介入。

四、踩坑与排障

坑 1:代理顺序装反现象:@GlobalTransactional加了但分支从未注册,Seata Server 查不到分支记录,回滚不生效。 排查:确认DataSourceProxy是最外层;若用了 ShardingSphere 编程式 API,检查是否把 Seata 数据源又包进了分片规则里。

坑 2:某个分库漏建 undo_log现象:单分库写入正常,一旦事务路由到那个库,注册分支时报"表不存在"或插入undo_log失败。 排查:对每个物理分库执行SELECT 1 FROM undo_log LIMIT 1逐一确认;多分库时容易只建了主库。

坑 3:表没有主键现象:对无主键表执行 UPDATE/DELETE 时分支注册失败或报错,全局锁无法锁定到行。 排查:lock_table中的pk字段存的就是主键值;要么补主键,要么评估把该表移出 AT 管理范围。

坑 4:vgroup 映射对不上现象:客户端启动正常,发起全局事务时报找不到 TC 地址/事务组。 排查:核对三处一致性——tx-service-group、vgroup-mapping的 key、Server 端注册的 cluster 名;用注册中心里实际注册条目比对。

坑 5:全局事务超时现象:大事务(含远程调用、人肉审批等待)走到一半被 TC 判超时回滚,前面的分支全部撤销。 排查:@GlobalTransactional的timeoutMills与server.session超时配置是否匹配;长流程应改用 Saga 而不是拉长 AT 超时。

坑 6:全局锁等待现象:并发下部分请求报全局锁获取失败/等待超时,QPS 上不去。 排查:看是否多个事务争抢同一行(热点行);能拆分就缩小单事务内的行范围,不能拆分就评估 TCC 或异步化。

五、适用性判断:什么时候不该用

  • 单库扛得住,就别拆:分库分表本身是容量问题,容量没到线时引入 ShardingSphere + Seata 只增加故障面。
  • 事务跨度以分钟计:AT 的全局锁窗口会很长,阻塞面大。这类流程用 Saga + 补偿,或干脆本地消息表做到达级一致。
  • 跨系统而非跨库:对方是独立服务、独立发布节奏时,AT 的"代理数据源"模型套不上,更适合 TCC、Saga 或消息最终一致。
  • 对延迟极敏感的读链路:Seata 代理连接对每条 DML 有额外处理开销(快照、注册),纯读流量不要走全局事务。
  • 强一致要求 + 超高并发写同一批行:AT 的全局行锁会先于数据库本地锁成为瓶颈,这是 2PC/TCC 都不划算、需要重新设计业务模型(如库存预扣减、合并写)的信号。

一个粗略的参考线(示例量级):日交易十万级、事务内步骤个位数、以库内写为主——AT 是性价比最高的起点;核心资金链路且并发极高——TCC;长流程编排——Saga。

六、结语

ShardingSphere 解决"数据放在哪",Seata 解决"多处写入如何同生共死",两者组合让跨库事务不需要业务重写 SQL,也不需要业务方自备补偿逻辑。落地时抓住三件事:每个分库的undo_log、数据源代理顺序、被操作表必须有主键,其余都是参数微调。AT 模式适合中短事务的跨库写场景,长流程与极端并发应分别交给 Saga 和 TCC,按事务特征选模式,比追新架构更可靠。

【免费下载链接】incubator-seata:fire: Seata is an easy-to-use, high-performance, open source distributed transaction solution.项目地址: https://gitcode.com/gh_mirrors/in/incubator-seata

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 1:38:46

neuroptica:可微分光学神经网络仿真框架

简介:本资源是面向光学计算与光子人工智能研究者的专业仿真工具包,专为光学神经网络(ONN)建模、设计与性能评估提供开源支持,适用于高校研究生、光电交叉领域工程师及AI硬件方向科研人员。包内共39个文件,以…

作者头像 李华
网站建设 2026/10/29 1:36:45

3个维度解析ECDICT:开源词典数据库的技术实现与应用价值

3个维度解析ECDICT:开源词典数据库的技术实现与应用价值 在数字化时代,词典工具已成为语言学习、应用开发和文本分析的基础设施。ECDICT作为一款完全开源的中英文词典数据库,通过本地化部署实现毫秒级离线查询响应,支持自定义扩展…

作者头像 李华
网站建设 2026/10/29 1:32:53

(五)安全规约的基础知识

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华