亿级分布式系统架构演进实战(十)- 垂直拆分(分布式事务管理设计)

亿级分布式系统架构演进实战(一)- 总体概要
亿级分布式系统架构演进实战(二)- 横向扩展(服务无状态化)
亿级分布式系统架构演进实战(三)- 横向扩展(数据库读写分离)
亿级分布式系统架构演进实战(四)- 横向扩展(负载均衡与弹性伸缩)
亿级分布式系统架构演进实战(五)- 横向扩展(缓存策略设计)
亿级分布式系统架构演进实战(六)- 横向扩展(监控与日志体系)
亿级分布式系统架构演进实战(七)- 横向扩展(安全防护设计)
亿级分布式系统架构演进实战(八)- 垂直拆分(领域划分及垂直分库设计)
亿级分布式系统架构演进实战(九)- 垂直拆分(服务间通信设计)

一、核心目标

解决跨服务数据一致性问题,平衡性能与一致性

  1. 强一致性:确保跨服务操作原子性,适用于金融等高敏感场景。
  2. 最终一致性:通过异步补偿机制,提升系统吞吐量和可用性。
  3. 可观测性:全链路监控事务状态,支持人工介入异常处理。

二、强一致性方案

1. Seata AT模式(自动补偿)

设计意图

简化开发 :通过全局锁机制自动回滚事务,减少业务侵入。

适用场景:电商订单创建(扣库存+生成订单)。

技术实现

全局事务ID(XID) :Seata客户端生成唯一ID,贯穿所有子事务。

数据快照:记录事务前后的数据镜像,用于自动回滚。

生产配置示例

yaml 复制代码
# Seata Server配置(Nacos注册中心)
seata:
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848

优劣势

优势 :开发简单,适合传统事务迁移场景。

劣势:全局锁可能导致性能瓶颈(建议分库分表优化)。


2. XA两阶段提交(数据库原生支持)

设计意图

强一致性保障:数据库原生支持,适合金融转账等高敏感场景。

技术实现

Phase 1(Prepare) :所有参与者锁定资源,返回准备状态。

Phase 2(Commit/Rollback):协调者根据Prepare结果提交或回滚。

代码示例

java 复制代码
// MySQL XA事务示例
XADataSource xaDataSource = ... // 获取XA数据源
XAResource xaRes = xaDataSource.getXAConnection().getXAResource();
Xid xid = new MyXid(); // 全局事务ID

try {
    xaRes.start(xid, XAResource.TMNOFLAGS);
    // 执行SQL操作(如扣款)
    xaRes.end(xid, XAResource.TMSUCCESS);
    xaRes.prepare(xid);
    xaRes.commit(xid, false); // 提交事务
} catch (XAException e) {
    xaRes.rollback(xid); // 回滚事务
}

优劣势

优势 :严格ACID,适合银行核心系统。

劣势:同步阻塞,性能较低(TPS < 500)。


3. TCC模式(手动补偿)

设计意图

灵活控制:通过Try-Confirm-Cancel三阶段,支持自定义补偿逻辑。

技术实现

Try :预留资源(如冻结库存)。

Confirm :提交事务(如确认扣减库存)。

Cancel:回滚预留(如解冻库存)。

代码示例

java 复制代码
public interface InventoryTccService {
    @TwoPhaseBusinessAction(name = "prepare", commitMethod = "confirm", rollbackMethod = "cancel")
    boolean prepare(BusinessActionContext context, @BusinessActionContextParameter(paramName = "skuId") String skuId, int count);
    
    boolean confirm(BusinessActionContext context);
    boolean cancel(BusinessActionContext context);
}

生产配置

幂等性保障 :通过唯一事务ID避免重复提交。

超时控制:设置Try阶段最长等待时间(如30秒)。

优劣势

优势 :高性能,适合秒杀等高并发场景。

劣势:开发复杂,需手动实现补偿逻辑。


三、最终一致性方案

1. Saga模式(正向+逆向补偿)

设计意图

长事务处理:通过事件驱动逐步执行事务,失败时逆向补偿。

技术实现

正向操作 :依次执行子事务(如创建订单 → 扣库存)。

补偿操作:逆向回滚(如取消订单 → 返还库存)。

代码示例

java 复制代码
// Saga流程定义(使用Apache Camel)
from("direct:createOrder")
    .saga()
    .compensation("direct:cancelOrder")
    .to("bean:orderService?method=createOrder")
    .to("bean:inventoryService?method=deductStock");

from("direct:cancelOrder")
    .to("bean:orderService?method=cancelOrder")
    .to("bean:inventoryService?method=restoreStock");

优劣势

优势 :支持复杂业务流程,适合电商订单。

劣势:补偿逻辑需覆盖所有失败场景。


2. 异步校对(定时补偿)

设计意图

数据最终一致:通过定时任务检测并修复不一致状态。

技术实现

定时任务 :扫描事务表,检查未完成的事务。

补偿触发:对异常事务执行修复(如重试或回滚)。

生产配置示例

sql 复制代码
-- 检测未完成订单
SELECT order_id 
FROM orders 
WHERE status = 'CREATED' 
  AND create_time < NOW() - INTERVAL '10 minutes';

优劣势

优势 :实现简单,适合对一致性要求不高的场景(如日志记录)。

劣势:修复延迟,可能影响用户体验。


3. 事务消息(RocketMQ)

设计意图

可靠消息投递:确保本地事务与消息发送的原子性。

技术实现

半消息 :消息暂存Broker,不可被消费。

事务状态回查:Broker定期检查生产者事务状态。

代码示例

java 复制代码
// 发送事务消息
TransactionSendResult result = producer.sendMessageInTransaction(message, order);
if (result.getLocalTransactionState() == LocalTransactionState.ROLLBACK_MESSAGE) {
    // 事务回滚处理
}

// 消费端幂等处理
if (redis.setnx(orderId, "PROCESSING") == 1) {
    inventoryService.deductStock(orderId);
}

优劣势

优势 :高吞吐量(TPS > 10k),适合订单创建场景。

劣势:依赖消息队列可用性。


4. 本地事务消息表

设计意图

去中心化事务:通过本地事务保证业务操作与消息写入的原子性。

技术实现

  1. 业务表与消息表在同一个事务中写入。
  2. 定时任务扫描消息表,发送消息到MQ。

数据库表设计

sql 复制代码
CREATE TABLE transaction_messages (
    id BIGINT PRIMARY KEY,
    topic VARCHAR(100),
    payload TEXT,
    status ENUM('PENDING', 'SENT'),
    created_time TIMESTAMP
);

优劣势

优势 :不依赖MQ事务消息功能,兼容性高。

劣势:需额外维护消息表,增加数据库压力。


5. Transactional Outbox

设计意图

可靠事件发布:通过数据库事务确保事件持久化,外部消费者轮询获取。

技术实现

  1. 业务操作与事件写入同一事务。
  2. 独立进程轮询事件表,发布到MQ。

代码示例

java 复制代码
// 发布事件
@Transactional
public void createOrder(Order order) {
    orderRepository.save(order);
    outboxRepository.save(new OutboxEvent("order_created", order.getId()));
}

优劣势

优势 :解耦业务与消息发送,适合微服务架构。

劣势:增加轮询开销,可能引入延迟。


四、事务生命周期与监控

1. 事务状态记录

唯一事务ID :全局唯一标识符(如UUID)。

状态跟踪:记录事务的开始、提交、回滚状态。

数据库表设计

sql 复制代码
CREATE TABLE transaction_logs (
    tx_id VARCHAR(36) PRIMARY KEY,
    service_name VARCHAR(50),
    status ENUM('STARTED', 'COMMITTED', 'ROLLBACKED'),
    created_time TIMESTAMP,
    updated_time TIMESTAMP
);

2. 监控与告警

核心指标

事务成功率 :统计各服务事务成功/失败比例。

延迟分布:P50、P90、P99事务处理时间。

告警规则

yaml 复制代码
# Prometheus告警配置
groups:
- name: transaction-alerts
  rules:
  - alert: HighTransactionFailureRate
    expr: sum(rate(transaction_failed_total[5m])) / sum(rate(transaction_total[5m])) > 0.05
    labels:
      severity: critical
    annotations:
      summary: "事务失败率超过5% (当前值: {{ $value }})"

人工介入流程

  1. 异常标记:监控系统标记状态为"待处理"的事务。
  2. 人工处理:通过管理后台查看详情,触发补偿或通知开发。

五、方案对比与选型建议

方案 一致性 性能 复杂度 适用场景
Seata AT 传统业务迁移
XA两阶段提交 金融转账
TCC 高并发秒杀
Saga 最终 长流程事务(电商订单)
事务消息 最终 异步通知场景
Transactional Outbox 最终 微服务解耦
相关推荐
敲键盘的小夜猫1 小时前
Redisson延迟队列实战:分布式系统中的“时间管理者“
java·redis·分布式
可爱的霸王龙2 小时前
SpringBoot整合JWT
java·后端·jwt
甜可儿2 小时前
Gateway实战入门(四)、断言-请求头以及请求权重分流等
java·spring cloud·gateway
爱的叹息2 小时前
Spring容器从启动到关闭的注解使用顺序及说明
java·后端·spring
三氧化真2 小时前
使用FastExcel时的单个和批量插入的问题
java·数据库·mybatis
蜡笔小祎在线学习2 小时前
小林coding-12道Spring面试题
java·后端·spring
杨凯凡3 小时前
Mockito 全面指南:从单元测试基础到高级模拟技术
java·单元测试·mockito
西陵3 小时前
一文带你吃透前端网站嵌入设计
前端·javascript·架构
厌世小晨宇yu.3 小时前
对Gpt关于泛型、Stream的提问
java·开发语言·gpt·ai
lllsure3 小时前
SpringMVC 拦截器(Interceptor)
java·开发语言·mysql