微服务架构下处理分布式事务的典型方案

传统数据库事务特性ACID

  1. 原子性(atomicity):事务是数据库的逻辑工作单位,而且是必须是原子工作单位,对于其数据修改,要么全部执行,要么全部不执行。
  2. 一致性(consistency):事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。
  3. 隔离性(isolation):一个事务的执行不能被其他事务所影响。
  4. 持久性(durability):一个事务一旦提交,事物的操作便永久性的保存在DB中。即使此时再执行回滚操作也不能撤消所做的更改。

分布式事务的讨论主要聚焦于强一致性和最终一致性的解决方案

  1. 两阶段提交(2PC) 和 三阶段提交(3PC)、paxos算法
  2. eBay事件队列方案
  3. TCC 补偿模式
  4. 缓存数据最终一致性

一般单机应用采用JavaJDBC事务控制即可

try {  
    conn.setAutoCommit(false); 
    //业务代码
    conn.commit();      
} catch (Exception e) {  
    conn.rollback();    
    e.printStackTrace();  
} 

分布式数据一致性

为了保证数据高可用,数据会存放在多个副本(replica)不同物理机器中,需要把保持这些数据的一致性,采用了常用的几种算法二阶提交(2PC)、三阶提交(3PC)Paxos算法

分布式事务

指会涉及到操作多个数据库的事务。目的是为了保证分布式系统中的数据一致性。

分布式事务处理的关键是必须有一种方法可以知道事务在任何地方所做的所有动作,提交或回滚事务的决定必须产生统一的结果(全部提交或全部回滚)

由于存在事务机制,可以保证每个独立节点的ACID,但是不能知道其他节点的执行情况,所以不能保证数据一致。要想多台机器的数据一致。必须保证在所有节点的数据写操作,要不全部都执行,要么全部的都不执行。解决方案就是通过引入一个“协调者”的组件来统一调度所有分布式节点的执行。

XA规范

X/Open 组织(即现在的 Open Group )定义了分布式事务处理模型包括应用程序( AP )、事务管理器( TM )、资源管理器( RM )、通信资源管理器( CRM )四部分。

XA 就是 X/Open DTP 定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。 XA 接口函数由数据库厂商提供。

二阶提交协议和三阶提交协议就是根据这一思想衍生出来的。
两阶段提交主要保证了分布式事务的原子性

2PC

所谓的两个阶段是指:准备阶段和提交阶段

两阶段提交算法思路:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作

但是两阶段提交可能出现一些问题:同步阻塞、单点故障、数据不一致等问题

二阶段无法解决:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交

3PC

在2PC基础上,新增超时机制和在第一阶段和第二阶段中插入一个准备阶段。

保证了在最后提交阶段之前各参与节点的状态是一致的(CanCommit阶段、PreCommit阶段、doCommit阶段)

2PC与3PC的区别

  1. 相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit
  2. 3PC也可能导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况

一致性理论

分布式最终目的是保障分库数据一致,但是会由于各种外界因素,而导致不可控因素(例如:个别节点永久性宕机、无法已知各个节点的事务状态。

2PC是分布式事务较为经典的方案,但是扩展性极差。eBay架构师提出了BASE理论为了解决大规模分布式系统下的数据一致性问题。BASE理论:可以通过放弃系统在每个时刻的强一致性来换取系统的可扩展性。

CAP理论

在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance3个要素最多只能同时满足两个。

  • 一致性:分布式环境下多个节点的数据是否强一致。
  • 可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。
  • 分区容忍性:特指对网络分区的容忍性。

举例:Cassandra、Dynamo等,默认优先选择AP,弱化C;HBase、MongoDB 等,默认优先选择CP,弱化A

BASE理论

核心思想

  • 基本可用(Basically Available):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。
  • 软状态(Soft State):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。
  • 最终一致性(Eventual Consistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态。

一致性模型

  • 强一致性:数据更新成功后,任意时刻所有副本中的数据都是一致的,一般采用同步的方式实现。
  • 弱一致性:数据更新成功后,系统不承诺立即可以读到最新写入的值,也不承诺具体多久之后可以读到。
  • 最终一致性:弱一致性的一种形式,数据更新成功后,系统不承诺立即可以返回最新写入的值,但是保证最终会返回上一次更新操作的值。   

分布式系统数据的强一致性、弱一致性和最终一致性可以通过Quorum NRW算法分析。

eBay 事件队列方案——最终一致性

核心思想

将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等

具体业务场景:

用户表user 和交易表transaction,用户表存储用户信息、总销售额和总购买额,交易表存储每一笔交易的流水号、买家信息、卖家信息和交易金额。如果产生了一笔交易,需要在交易表增加记录,同时还要修改用户表的金额

提出的解决方法是将更新交易表记录和用户表更新消息放在一个本地事务来完成

为了避免重复消费用户表更新消息带来的问题,增加一个操作记录表updates_applied来记录已经完成的交易相关的信息

TCC (Try-Confirm-Cancel)补偿模式——最终一致性

服务A 需要依次调用服务B、服务C 和服务D 共同完成一个操作。当服务A 调用服务D 失败时,若要保证整个系统数据的一致性,就要对服务B 和服务C 的invoke 操作进行回滚,执行反向的revert 操作。回滚成功后,整个微服务系统是数据一致的

实现关键要素

1.服务调用链必须被记录下来;
2.每个服务提供者都需要提供一组业务逻辑相反的操作,互为补偿,同时回滚操作要保证幂等;
3.必须按失败原因执行不同的回滚策略。

实现难点

  1. 补偿模式的特点是实现简单,但是想形成一定程度的通用方案比较困难,特别是服务链的记录,因为大部分时候,业务参数或者业务逻辑千差万别。
  2. 很多业务特征使得该服务无法提供一个安全的回滚操作。

缓存数据最终一致性

在具体业务系统中,缓存通常被用在数据库前面,作为数据读取的缓冲,使得I/O 操作不至于直接落在数据库上

###缓存和数据库数据不一致的问题解决方案

  1. 为缓存数据设置过期时间。当缓存中数据过期后,业务系统会从数据库中获取数据,并将新值放入缓存。这个过期时间就是系统可以达到最终一致的容忍时间
  2. 更新数据库数据后同时清除缓存数据。数据库数据更新后,同步删除缓存中数据,使得下次对商品详情的获取直接从数据库中获取,并同步到缓存

分布式事务具体实例

参考

分布式系统事务一致性到CAP,BASE理论

企鹅讲解分布式事务

网易云分布式架构解决方案