导读:本文介绍了分布式事务的属性,事务的隔离级别具体的作用,分布式事务的解决方案,同时说明了我们的分布式事务:用友微服务治理平台提供的一个核心功能组件。
分布式事务介绍
什么是分布式事务
分布式事务就是指事务的资源分别位于不同的分布式系统的不同节点之上的事务;
例如:信用卡还款,包含两个操作
·从银行账户扣钱
·恢复信用卡额度
·例子中两个操作如果处于不同的数据库,或者根本就是两个微服务中的操作,想要保证数据的一致性,靠本地事务是解决不了的,这时候就需要分布式事务了。
事务属性
原子性(Atomicity)
事务中的所有操作,要么都成功,要么都失败,不可能部分操作成功部分操作失败。事务的操作或者完全应用到数据库或者完全不影响数据库。
拿信用卡还款来说,原子性就是银行账户扣钱和信用卡额度恢复要么都成功要么都失败。
一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿信用卡还款来说,一致性就是还款成功前和还款后银行卡余额加上信用额度是相等的。
隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍。
持久性(Durability)
在事务成功以后,该事务对数据库所做的更改应当持久的保存在数据库中;
总结来说, 一致性是最基本的属性,而原子性、隔离性、持久性是为了保证一致性而存在的。
事务的隔离级别
事务的隔离级别有什么用呢?我们先看一下不考虑事务的隔离性会出现那些问题。
脏读
时间轴为5的地方事务B就出现了脏读
不可重复读
事务B中两次查询结果并不一样。不可重复读和脏读的区别是不可重复读是读取了另一个事务提交的数据。
幻读
MySQL数据库为我们提供的四种隔离级别:
分布式事务解决方案
TCC(Try-Confirm-Cancel)
·TCC是由支付宝架构师提供的一种柔性解决分布式事务解决方案,主要包括三个步骤
·Try: 完成业务检查,预留必须的业务资源
·Confirm: 真正的执行业务逻辑,不做任何业务检查,只使用Try阶段预留的业务资源。所以,只要Try执行成功,Confirm必须能成功。Confirm必须满足幂等性,保证一次分布式事务只成功一次。
·Cancel: 释放Try阶段预留的业务资源。Cancel也需要满足幂等性
TCC自编码的特性决定TCC资源管理器可以跨DB、跨应用实现资源管理,将对不同的DB访问、不同的业务操作通过编码方式转 换一个原子操作,解决了复杂业务场景下的事务问题;
在整个流程,我们主要需要关注的是cancel失败和confirm失败引起的数据不一致现象。
TCC模式要求从服务提供三个接口:Try、Confirm、Cancel.而且Confirm、Cancel需要满足幂等性。这将大大增加了开发难度。
事务自动补偿
我们肯定都想和之前一样编写代码,但是运行的时候程序会自动帮你保证事务的一致性。在TCC模式中就是程序自动帮你Cancel,相当于框架帮你写好了Cancel,并在异常的时候执行Cancel.这就是事务自动补偿。
框架托管FMT(Framework-managed transactions)模型
FMT是阿里GTS(全局事务服务)中的一个可以实现自动补偿事务的模型。
FMT 框架要求从业务服务只需要正常执行SQL操作就可以了,框架会把业务的本地事务操作作为第一阶段。在第一阶段,框架会拦截用户SQL,解析SQL语义,然后把业务SQL涉及数据执行前后的状态保存下来,即数据快照,这个就相当于在逻辑上完成了数据库内的undo和redo操作。在第二阶段,如果这个事务要提交,那么框架直接把快照数据删除就可以了,因为第一阶段的正常操作已经执行完成。如果该事务要回滚,那么会先校验脏写,根据第一阶段保存的执行后的快照,检查在本事务执行过程中,数据有没有被其他操作修改,如果没有,则把数据执行前的快照拿出来,完成回滚操作。
GTS的限制
GTS用于实现分布式环境下高性能事务一致性。可以与DRDS、RDS、MySQL、PostgreSQL等数据源,EDAS、Dubbo及其他RPC框架,MQ消息队列等中间件产品配合使用,轻松实现分布式数据库事务、多库事务、消息事务、服务链路级事务及各种组合。
使用GTS(全局事务服务 - Global Transaction Service)也有很大的限制的,比如下图:
1.把一个sql解析为抽象语法树时,sql越复杂解析越耗时。所以复杂的sql使用FMT是非常不值得的,在复杂的业务逻辑面前事务的自动补偿这个功能就显得很鸡肋了。
2.GTS的隔离级别默认为读未提交。当更新数据时很容易出现脏写。这时候如果出现错误,Cancel校验脏写就会出现错误恢复快照导致已经修改的数据被覆盖。
3.GTS提供的hint模式是针对阿里自研的DRDS.当你使用非DRDS时列如mysql时,使用了for update,这样将会大大降低性能
4.不能使用聚合函数。读未提交时聚合函数不一定准确(脏读)。读已提交时不支持聚合函数。
5.当插入/更新数据数量太多时保存快照的消耗太大。而且快照是否持久化也是一个问题
6.没有解决幻读问题
总结
综上所述,事务的自动补偿是没有必要的。对于简单的业务逻辑不需要,对于复杂的业务逻辑现在的事务自动补偿达不到要求,想要性能好必须要做好脏读、幻读的准备,想要读已提交必须要舍弃性能。所以目前阶段还是使用TCC比较合适。
我们的分布式事务
CCTransaction分布式事务框架是解决微服务开发环境中,事务一致性问题而提出的一种解决方案,与TCC分布式事务一致性方案不同,CCTransaction是一个没有事务协调器、没有事务中心概念,事务由各个参与者功能完成整个事务的管理,是用友微服务治理平台提供的 一个核心功能组件。
·解决分布式事务一致性问题,业务使用分布式事务一致性功能只需两个注解, @CCTransactional(cancel=“cancelOrder”)标识业务方法需要使用分布式事务 cancel属性指定了业务异常时的补偿方法,与业务方法在同一个接口中实现,补偿方法上加入 @Async注解
·基于可靠消息的异步调用框架(EOS)的最终一致性
·支持链式rpc调用中各个业务节点的事务一致性
·基于用友微服务治理平台rpc框架Iris
·事务信息数据与业务库一起,由框架自行操作,用户无需关心
我们的TCC框架已经内测中,想要使用更多功能,请关注我们服务治理平台。
我的思考: 我们是不是可以在程序端保证原子性和隔离性。
这样也是可以保证真正的读已提交。