您现在的位置是:网站首页 > 心得笔记
分布式事务
分布式事务定义
分布式事务是指在分布式系统中,一次操作由多个系统协同完成,这种一次事务操作涉及多个系统通过网络协同完成的过程。这些系统可能分布在不同的物理机器或多个不同的系统中,每个系统可能管理着不同的资源,如数据库、消息队列、缓存等。
分布式事务特点
多节点参与:分布式事务涉及多个节点,这些节点可能分布在不同的地理位置和网络环境中。
网络部可靠性:在分布式系统中,网络可能会延迟、丢包甚至中断,这会导致事务操作失败或超时。
一致性问题:由于分布式系统中数据分布在不同的节点上,如何保证多个节点上的数据一致性是一个难题。
复杂性:实现和维护分布式事务比单体事务复杂得多,需要更多的协调和处理机制。
如何处理分布式事务
1.类似于资金等特别严格的场景,用的是 TCC 来保证强一致性
2.一般的分布式事务场景,如订单插入之后要调用库存服务更新库存,库存数据没有资金那么的敏感,用MQ 来实现分布式事务
TCC方案
TCC的全称是:Try、Confirm、Cancel,尝试 确认 取消,是一种常见的分布式事务解决方案,用于解决分布式系统中的事务一致性问题。
Try 阶段:这个阶段说的是对各个服务的资源做检测以及对资源进行锁定或者预留。
public boolean tryTransfer(String fromAccount, String toAccount, BigDecimal amount) { // 1. 扣减账户A的金额(假设调用扣减接口) boolean debitResult = accountService.debit(fromAccount, amount); // 2. 增加账户B的金额(假设调用增加接口) boolean creditResult = accountService.credit(toAccount, amount); // 返回尝试阶段是否成功 return debitResult && creditResult; }
Confirm 阶段:这个阶段说的是在各个服务中执行实际的操作。在确认阶段,会更新事务的状态,标记事务已经成功执行并提交。这些状态的更新通常会记录在事务管理器、或者相关的事务日志中,以便后续的监控和恢复操作。
public void confirmTransfer(String fromAccount, String toAccount, BigDecimal amount) { // 实际执行转账操作(扣减账户A,增加账户B) transferService.transfer(fromAccount, toAccount, amount); }
Cancel 阶段:如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,就是执行已经执行成功的业务逻辑的回滚操作。(把那些执行成功的回滚)。在取消阶段,系统会执行与尝试阶段相反的操作,回滚所有在尝试阶段预留的操作。在取消阶段,会更新事务的状态,标记事务已经被取消或者回滚。这些状态的更新通常会记录在事务管理器、或者相关的事务日志中,以便后续的监控和恢复操作。
public void cancelTransfer(String fromAccount, String toAccount, BigDecimal amount) { // 回滚账户A的扣减操作 accountService.rollbackDebit(fromAccount, amount); // 回滚账户B的增加操作 accountService.rollbackCredit(toAccount, amount); }
TCC应用场景
融交易:如转账、支付等操作,需要保证资金的安全性和一致性。
订单处理:包括:创建订单、扣减库存、支付...等多个步骤,需要确保订单状态的一致性。
业务流程:如审批流程、工作流......等,涉及多个步骤的业务操作。
本地消息表(异步确保)
本地消息表与业务数据表处于同一数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。
在分布式事务操作的一方完成写业务操作后向本地消息表发送一个消息,本地事务能确保这个消息一定会被写入本地消息表中。
之后将本地消息表中的消息转发到kafka等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。
在分布式事务操作的另一方从消息队列中读取消息,并执行消息中的操作。
MQ事务消息
有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不支持。
基于MQ来实现事务
上一篇:mysql的三范式