设计方案

分布式事务,这一篇就够了

2020-04-19  本文已影响0人  45534c874741

说在前面

  近几年互联网的快速发展已经改变了我们的生活,比如可以足不出户的进行办理银行业务、点外卖等等。而对应的互联网系统随着业务越来越复杂,其架构模型也与时俱进的产生了一些变化。分布式、微服务架构,大家对此一定不陌生,现在如果问拆分微服务的好处,大家都可以想到一大堆,比如开发冲突问题、解耦、独立弹性部署等。
  然而事物都有两面性,带来好处的同时,肯定也会带来一些问题,今天我们要谈的就是分布式架构带来的其中一个无法回避的问题:分布式事务
下面将按照以下的顺序来讲解:


什么是事务

  事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元。简单来说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制。比如交易时一手交钱,一手交货。


单机事务

  单机事务一般指数据库本地事务,是由数据库服务(如mysql)自身提供的一种事务实现,说起数据库事务,一定绕不开ACID,即:


分布式事务

定义:一个操作分为很多小的操作,这些小的操作位于不同的服务器之上,保证这些小操作要么全部成功,要么全部失败。本质上是保证不同数据库(存储)的数据一致性。

产生背景

  总结来看有2个原因导致了分布式事务的产生:

理论基础

  从上面来看分布式事务是随着互联网高速发展应运而生的,这是一个必然。
我们之前说过数据库的 ACID 四大特性,已经无法满足我们分布式事务,这个时候又有一些新的大佬提出一些新的理论。


CAP与BASE理论.png
CAP理论:又被称布鲁尔定理,对于一个分布式计算系统,不可能同时满足一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三个设计约束。

关于CAP,这里补充2点:

BASE理论:基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency)

  BASE理论是CAP理论中AP的延伸,是对互联网大规模分布式系统的实践总结,强调可用性。从CAP理论得知,在分布式系统中实现强一致性必然影响可用性,几乎所有的互联网系统采用的都是最终一致性,只有在决定系统运行的敏感元数据,才考虑采用强一致性,比如与钱相关的支付系统或者金融系统的数据。

下面将介绍几种常见的分布式事务解决方案及它们适用的一致性要求场景:

主流解决方案

是否真的需要分布式事务

在说方案之前,首先你一定要明确你是否真的需要分布式事务?

上面说过出现分布式事务的两个原因,其中有个原因是因为服务化拆分,在选择分布式事务解决方案之前,先分析下能否把需要事务的微服务聚合成一个单机服务,使用数据库的本地事务。

因为不论任何一种方案都会增加系统的复杂度,千万不要因为追求某些设计,而引入不必要的成本和复杂度。

如果你确定需要引入分布式事务可以看看下面几种常见的方案。

方案一:2PC(强一致模型)

典型代表 XA Transactions:X/Open 组织提出的分布式事务处理的规范,定义了事务管理器(Transaction Manager)和局部资源管理器(Local Resource Manager)之间的接口。


XA.png

在 XA 协议中分为两阶段:

优点:

缺点:

总的来说,XA 协议比较简单,成本较低,但是其单点问题,以及不能支持高并发(由于同步阻塞)依然是其最大的弱点,所以在互联网系统极少使用。

方案二:TCC(强一致模型)

关于 TCC(Try-Confirm-Cancel)的概念,最早是由 Pat Helland 于 2007 年发表的一篇名为《Life beyond Distributed Transactions:an Apostate’s Opinion》的论文提出。


TCC.png

不同于XA实现在资源层,TCC是一种服务层的二阶段协议,业务开发者需要实现这三个服务接口,第一阶段服务由业务代码编排来调用 Try 接口进行资源预留,所有参与者的 Try 接口都成功了,事务管理器会提交事务,并调用每个参与者的 Confirm 接口真正提交业务操作,否则调用每个参与者的 Cancel 接口回滚事务。

TCC不与具体的服务框架耦合,与底层 RPC 协议无关,与底层存储介质无关,可以灵活选择业务资源的锁定粒度,减少资源锁持有时间,可扩展性好,可以说是为独立部署的 SOA 服务而设计的。
使用TCC时,大部分工作都集中在如何实现 TCC 服务(即TCC需要提供的三个接口)上,使用TCC的主要事项(限于篇幅关系,这里只列出大纲,详细可参考文末参考链接部分):
1、将业务操作分2阶段完成
  接入 TCC 前,业务操作只需要一步就能完成,但是在接入 TCC 之后,需要考虑如何将其分成 2 阶段完成,把资源的检查和预留放在一阶段的 Try 操作中进行,把真正的业务操作的执行放在二阶段的 Confirm 操作中进行。比如在账户余额增减时,增加冻结金额含义。
2、并发控制
  接口上降低锁粒度,提高并发
3、允许空回滚
  Try网络超时后执行二阶段Cancel,此时并没有收到Try,造成空回滚
4、防悬挂控制
  Confirm或Cancel比Try先到,TCC 服务在执行晚到的 Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel ,造成 TCC 服务悬挂
5、幂等处理
  网络重传或异常事务补偿执行,均会造成被重复执行。
优点:强一致,性能高
缺点:强侵入业务,业务需改造,实现难度高、复用度低
适用场景:强隔离、要求严格一致性的业务,执行时间较短的业务,比如交易、支付、账务服务

方案三:基于异步可靠消息(最终一致性模型)

核心是将需要分布式处理的任务通过消息日志的方式来异步执行,适用于最终一致性,对异步服务的执行时间敏感度低的业务。因为无法保证消息有且只投递一次,这种方案需要消费方实现幂等。

方案四:Saga(最终一致性模型)

金融核心上的业务(比如在渠道层、产品层、集成层的系统),这些系统的特点是最终一致即可、流程多、流程长、还可能要调用其它公司的服务(如金融网络),无法要求其它公司的服务也遵循 TCC 这种开发模式,同时流程长,事务边界太长会影响性能。所以对于更多的金融核心以上的业务系统可以采用补偿事务,补偿事务处理方面在30年前就提出了 Saga 理论,随着微服务的发展,近些年才逐步受到大家的关注。目前业界比较也公认 Saga 是作为长事务的解决方案。
核心思想:将长事务拆分为多个本地短事务,由 Saga 事务协调器协调
两种模式:向前恢复(T1,T2,T3,...,Tn),向后恢复(T1,T2,...,Tj,Cj,...,C2,C1)


saga.png

同TCC模型一样设计到多个阶段,所以补偿服务也要处理好空补偿、防悬挂及幂等补偿问题。
优点:

缺点:

适用场景:

社区和业务的方案有:

开源框架

Seata 意为:Simple Extensible Autonomous Transaction Architecture,是一套一站式分布式事务解决方案,提供了 AT、TCC、Saga 和 XA 事务模式。
项目地址:https://github.com/seata/seata
由蚂蚁金服的fescar演进而来,经历了双11的考验,同时对safa、dubbo、springcloud接入做了适配层。
关于seata的设计与实现,另文分析。

最后

设计系统时尽量不要依赖分布式事务,如果非得使用的话,结合自己的业务分析,看看自己的业务比较适合哪一种,是在乎强一致,还是最终一致即可。这里举几个不同的场景使用不同的分布式事务解决方案:

这篇文章是在现有大量已有资料做的一个整理,感谢行业内的“巨人们”,还要特别感谢boxer和antony提供的参考资料,希望大家看完后有一点点收获,也欢迎共同探讨。

参考资料:

[1] TCC 理论及设计实现指南介绍:https://seata.io/zh-cn/blog/tcc-mode-design-principle.html
[2] 基于 Seata Saga 设计更有弹性的金融应用:https://seata.io/zh-cn/blog/design-more-flexable-application-by-saga.html
[3] 分布式事务详解:https://mp.weixin.qq.com/s/T-Q9eouj4unrWh8Q9bJoOA

上一篇 下一篇

猜你喜欢

热点阅读