接受”不完美“:分布式事务学习总结

做为一个前端专业的人来讲,对于事务的理解,一直停留在“要么都成功,要么都不成功”的小白阶段。既然本身将2018年定义为”深刻理解“的一年,那么就从深刻理解事务开始吧。前端

什么是事务?

正如文章开头所说的:事务是一系列的动做,这些动做必须所有完成,若是有一个失败,那么事务就会回滚到最开始的状态,仿佛什么都没发生过同样。在企业级应用的开发过程当中,事务管理是必不可少的技术,用来确保数据的完整性和一致性。数据库

事务有四个特性,也就是常常被提到的ACID:编程

  • 原子性(Atomicity):所谓的原子性就是说,在整个事务中的全部操做,要么所有完成,要么所有不作,没有中间状态。对于事务在执行中发生错误,全部的操做都会被回滚,整个事务就像从没被执行过同样。
  • 一致性(Consistency):事务的执行必须保证系统的一致性,就拿转帐为例,A有500元,B有300元,若是在一个事务里A成功转给B50元,那么无论并发多少,无论发生什么,只要事务执行成功了,那么最后A帐户必定是450元,B帐户必定是350元。
  • 隔离性(Isolation):所谓的隔离性就是说,事务与事务之间不会互相影响,一个事务的中间状态不会被其余事务感知。
  • 持久性(Durability):所谓的持久性,就是说一单事务完成了,那么事务对数据所作的变动就彻底保存在了数据库中,即便发生停电,系统宕机也是如此。

上面咱们说到的事务,也能够称为是”本地事务“。目前许多框架,都可以很方便的支持本地事务。好比Spring Boot,只须要在方法前加上”@Transaction“的注解,就能够愉快的使用事务了。安全

可是,事务到此未知就结束了吗?不是的,随着企业应用愈来愈复杂,应用的架构也从单体架构演变到了SOA,还有如今煊赫一时的微服务。这时候,又出现了分布式事务的概念。网络

分布式事务

分布式事务,简单来讲就是指对数据库的处理操做分布在不一样的节点之上,并且操做的数据,分布于不一样的数据库。分布式事务,须要保证不一样数据库的数据一致性。架构

分布式事务产生的缘由

数据库分库分表

处于数据量或者数据隔离的考虑,实际开发中须要进行分库分表。原来一个库如今变成了多个库,这时候要保证数据一致性,就要用到分布式事务。
异步确保型并发

应用SOA化

所谓的SOA话,就是业务的服务化。好比原来单机支撑了整个电商网站,如今对整个网站进行拆解,分离出了订单中心、用户中心、库存中心。对于订单中心,有专门的数据库存储订单信息,用户中心也有专门的数据库存储用户信息,库存中心也会有专门的数据库存储库存信息。这时候若是要同时对订单和库存进行操做,那么就会涉及到订单数据库和库存数据库,为了保证数据一致性,就须要用到分布式事务。
app

CPA与BASE

说到分布式事务,就离不开CPA原则与BASE方案。框架

CPA

CPA指的是,在一个分布式系统中,一致性(C)、可用性(A)、分区容错性(P),三者不可兼得。CPA是NoSQL数据库的基石。异步

  • 一致性:在分布式系统中的全部数据备份,在同一时刻是否一样的值。(等同于全部节点访问同一份最新的数据副本)
  • 可用性:在集群中一部分节点故障后,集群总体是否还能响应客户端的读写请求。(对数据更新具有高可用性)
  • 分区容错性:以实际效果而言,分区至关于对通讯的时限要求。系统若是不能在时限内达成数据一致性,就意味着发生了分区的状况,必须就当前操做在C和A之间作出选择。

CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而因为当前的网络硬件确定会出现延迟丢包等问题,因此分区容忍性是咱们必须须要实现的。因此咱们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。

BASE

BASE就是为了解决关系数据库强一致性引发的问题而引发的可用性下降而提出的解决方案。

BASE是下面三个术语的缩写:

  • 基本可用(Basically Available)
  • 软状态(Soft state)
  • 最终一致(Eventually consistent)

常见的分布式事务解决方案

两阶段提交

两阶段提交(Two Phase Commit, 2PC), 具备强一致性, 是CP系统的一种典型实现,常见的标准是XA,JTA等。例如Oracle的数据库支持XA。

下面是两阶段提交的示意图:
异步确保型
图的上半是两阶段提交成功的演示, 下半是两阶段提交失败的演示。

两阶段提交目前并非主流的解决方案,其主要缘由是:协调者须要等待全部参与者发出yes请求,或者一个参与者发出no请求后,才能执行提交或者终端操做。这会形成长时间锁住多个资源,形成性能瓶颈。若是参与者有一个耗时长的操做, 性能损耗会更明显;还有一个缺点,就是实现复杂,不利于系统的扩展。

TCC(Try-Confirm-Cancel)

TCC, 是基于补偿型事务的AP系统的一种实现, 具备最终一致性。所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操做。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,若是更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是经过代码人为实现了两阶段提交,不一样的业务场景所写的代码都不同,复杂度也不同,所以,这种模式并不能很好地被复用。

异步确保型

经过将一系列同步的事务操做变为基于消息执行的异步操做, 避免了分布式事务中的同步阻塞操做的影响。基于消息执行就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操做成功成功而且对外发消息成功,要么二者都失败,开源的RocketMQ就支持这一特性,具体原理以下:
异步确保型

执行步骤以下:

  1. MQ发送方发送远程事务消息到MQ Server;
  2. MQ Server给予响应, 代表事务消息已成功到达MQ Server.
  3. MQ发送方Commit本地事务.
  4. 若本地事务Commit成功, 则通知MQ Server容许对应事务消息被消费; 若本地事务失败, 则通知MQ Server对应事务消息应被丢弃.
  5. 若MQ发送方超时未对MQ Server做出本地事务执行状态的反馈, 那么须要MQ Servfer向MQ发送方主动回查事务状态, 以决定事务消息是否能被消费.
  6. 当得知本地事务执行成功时, MQ Server容许MQ订阅方消费本条事务消息.

须要额外说明的一点, 就是事务消息投递到MQ订阅方后, 并不必定可以成功执行. 须要MQ订阅方主动给予消费反馈(ack)

  • 若是MQ订阅方执行远程事务成功, 则给予消费成功的ack, 那么MQ Server能够安全将事务消息移除;
  • 若是执行失败, MQ Server须要对消息从新投递, 直至消费成功.
  • 根据业务逻辑的具体实现不一样,还可能须要对消息中间件增长消息不重复, 不乱序等其它要求.

此方案适用于执行周期较长,实时性要求不高的场景。

最大努力通知型

这是分布式事务中要求最低的一种, 也能够经过消息中间件实现, 与前面异步确保型操做不一样的一点是, 在消息由MQ Server投递到消费者以后, 容许在达到最大重试次数以后正常结束事务.这种方案适用于交易结果消息的通知等

微服务的事务

最近两年,微服务的呼声愈来愈高,不可避免的,微服务也会面临事务的困扰。

  • 首先,对于微服务架构来讲,数据访问变得更加复杂,这是由于数据都是微服务私有的,惟一可访问的方式就是经过 API。这种打包数据访问方式使得微服务之间松耦合,而且彼此之间独立,更容易进行性能扩展。
  • 其次,不一样的微服务常用不一样的数据库。应用会产生各类不一样类型的数据,关系型数据库并不必定是最佳选择基于微服务的应用通常都使用 SQL 和 NoSQL 结合的模式。可是这些非关系型数据大多数并不支持 2PC。

总结

事务,尤为是分布式事务,是一个很大的话题,除了上述列出的几种解决方案,根据不一样的业务要求,还有许多其余的解决方案。按照控制力度,分布式事务分为部分控制和彻底控制两种:

  • 部分控制就是各类变种的两阶段提交,包括上面提到的异步确保型、TCC模式
  • 彻底控制就是彻底实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数据一致性减弱了,彻底控制则是牺牲了性能,保障了一致性。具体用哪一种方式,最终仍是取决于业务场景。
相关文章
相关标签/搜索