分布式大家都肯定了解吧,事务大家也肯定都不陌生,那么分布式事务是什么呢?
让我理解的话,我举一个例子来讲解,在我们电商项目中,我们的订单服务和支付服务是两个独立的模块,部署在不同的服务器上,按道理来说当我们订单创建成功后开始支付,如果都成功,ok,当然没有任何问题,但是这时候如果我们支付失败,按道理我们的订单也应该回滚,但是这时候我们的普通的事务(@Transactional)能否回滚两个不通服务器上的服务呢?肯定是不行的,这时候就需要我们的分布式事务。
本章的分布式事务是根据龙果学院的视频学习的,如有侵权请联系我删除
分布式事务初识
我们首先以电商购物支付流程来分析
我们可以看看上面的流程:
(1)电商平台中创建订单:预留库存,预扣减积分,锁定优惠券,此时电商平台内各服务间会有分布式事务问题,因为此时已经要跨多个内部服务修改数据。
(2)支付平台中创建支付订单(选银行卡支付):查询账户,查询限制规则,符合条件的就创建支付订单并跳转到银行,此时不会又分布式事务问题,因为还不会跨服务修改数据,多数数据是进行查询。
(3)银行平台中创建交易订单:查找账户,创建交易记录,判断账户余额并扣款,增加积分,通知支付平台,此时也会有分布式事务问题;
(4)支付平台收到银行的扣款结果;更改订单状态,给账户加款,给积分账户增加积分,生成会计分录,通知电商平台等,此时也会有分布式事务问题;
(5)电商平台收到支付平台的支付结果;更改订单状态,扣减库存,扣减积分,使用优惠券,增加消费积分等,系统内部各服务间调用也会遇到分布式事务问题。
个人总结下,我认为只要是跨系统进行数据的修改的时候,就涉及分布式事务。
- 支付平台收到银行扣款结果后的内部处理流程
(1)支付平台的支付网关对银行通知结果进行校验,然后调用支付订单服务执行支付订单处理。
(2)支付订单服务根据银行扣款结果更改支付订单状态。
(3)调用资金账户服务给电商平台的商户账户加款。
(4)调用积分服务给用户积分账户增加积分。
(5)调用会计服务向会计系统写入交易记录。
(6)调用通知服务将支付处理结果通知电商平台。
我们用简单的代码实现下:
/**
* 支付订单处理
**/
@Transactional(rollback = Exception.class)
public void completeOrder(){
// 订单服务本地更新订单状态, 该服务是本地服务
orderDao.update();
// 调用资金账户服务给资金账户加款
accountService.update();
// 调用积分服务给积分账户增加积分
pointService.update();
// 调用会计服务写入交易记录
accountingService.insert();
// 调用商户通知服务向商户发送支付结果通知
merchanNotifyService.notify();
}
我们可以看到我们在上面使用了@Transactional本地事务控制,这能够生效么?很明显是不行的,本地事务已经没有办法控制各个微服务间的调用的事务了。
在原有系统中加入分布式事务
我们既然已经没有办法用本地事务解决,那么我们应该如何在原有的系统中加入分布式事务呢?
由上图可知当银行支付成功后,支付结果回调,结果需要通知给通知服务和订单服务,此时这几个服务之间就涉及了分布式的事务。我们在这里加入了可靠消息服务。并在订单服务和资金账户服务之间加入了TCC的分布式事务特点。
- 我们先了解下后面我们会详细介绍的几种分布式事务的解决方案:
(1)基于可靠消息的最终一致性方案(异步确保型),适用场景较广。
可靠消息服务方案的特点:
- 可以独立部署,独立伸缩
- 兼容所有实现JMS标准的MQ中间件
- 能降低业务系统与消息服务之间的耦合
- 可实现数据可靠的前提下确保最终一致性。
(2)TCC事务补偿性方案(也属于两阶段的一种实现,但区别与2PC协议的两阶段提交)
TCC方案的特点
- 不与具体的服务框架耦合(在RPC框架中使用)
- 位于业务服务层,而非资源层
- 可以灵活的选择业务资源的锁定粒度
- 适用于强隔离性,严格一致性要求性强的业务场景
- 适用于执行时间较短的业务
(3)最大努力通知型方案