分布式事务那些事
Posted chen陈序猿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式事务那些事相关的知识,希望对你有一定的参考价值。
最近打算在年底完成的两个框架是分布式事务框架,意在解决分布式环境下的数据一致性,所以今天想聊聊分布式事务的那些事。
什么是事务
事务大家都很好理解。就是关系型数据库和部分非关系型数据库(如新版本Mongo)对应用提供的来保证数据强一致性的ACID特性。在一个业务的发起中,数据库能保证一个会话所提交的一系列sql操作,要么全部成功,要么全部失败。事务的特性保障了我们的业务数据可以在正确编码的正确性,所以十分重要。
在传统的单机应用时代。后台的服务架构长这样:
应用直连后台,后台直连数据库(如mysql)。
事务的声明也更简单:
在业务操作前,给mysql发送指令:begin;
业务操作完成给mysql发送指令:commit;
业务发生异常给mysql发送指令:rollback;
在一些封装度高的应用中,一个@transactional注解,搞定一切。
什么是分布式事务
随着业务的庞大和臃肿,项目的拆分和微服务化日渐有趋势。要不然维护一个巨无霸系统相当难受。微服务下,一个业务,可能是这个架构:
service1有自己的业务数据库。但service1还是要调用service2和service3。由于三个服务使用了3个独立的数据库。并不能通过强一致的数据库层面的事务来保证数据完整性。这时候,就需要另外的事务解决方案,这就是分布式事务。
简单举个例子:假设service1调用service2,service1调用超时,回滚掉了本地的事务,但是service2实际上收到了调用请求,如果执行成功,则会出现db1 rollback,db2 commit;数据错误。
我们可以知道,在分布式环境下,网络一定要考虑成不稳定的因素。优秀的程序员一定会思考网络不稳定了事务无法完成该怎么办?
我们可以知道,根据墨菲定律,可能发生的事情就一定会发生。所以......
分布式事务在多数公司的应用现状
在大型公司:
一,编写专门的分布式事务框架,保证分布式业务的数据一致性。如阿里的GTS。
二,放弃分布式事务,70%的业务实际上并没有那么强的强一致性要求,比如业务日志,比如说论坛系统点赞,评论等。允许适度丢失。所以有些公司由于业务属性,也没有直面分布式事务。但是,和支付相关的强一致场景,就痛苦了。
在中小型公司:
一,工期追赶,压根不考虑分布式事务,实际上在业务上线以后,很多系统都是直接调用,没有完善的数据一致性检查机制。业务实际上处于数据裸奔状态。你会经常看到修数据的场景发生。修的数据就是因为业务状态不一致产生的错误数据。
这其实是一个成本取舍的问题,因为技术领导者可能会认为:网络异常是小概率事件,考虑分布式事务太复杂了,所以就修数据吧。
二,针对每一个业务场景设计很多的中间状态和幂等检查。为了保证1%的网络问题造成的数据错误,业务开发周期可能要延长两到三倍。
总结:
正所谓,软件的事,没有什么是多加一层解决不了,如果解决不了,那就再加一层。程序员要做的事情不就是不断的抽象么,于是基于业务模型之前,就有了很多的分布式事务解决方案。他们各有好坏。你看,阿里都卖起了全局事务服务:
据笔者不怎么完善的了解,貌似GTS是要接管业务数据的数据源,整个实现修改了数据库默认的隔离级别,相当于魔改数据库。
分布式解决方案-两阶段提交
DTP模型-标准分布式事务:
这里涉及到两个协议:
TX协议:应用与全局事务管理器交互的协议
XA协议:全局事务管理器与资源管理器的交互
两阶段提交:
事务管理器发起准备命令(第一阶段)
资源管理器去执行每个服务的数据操作,(只执行业务操作sql,但不commit,这时候,就是锁定状态)
事务管理器搜集资源管理器的执行结果,只要有一个准备阶段发生错误,则告知各个资源管理器去执行rollback,否则,commit。(第二阶段)。如下图:
在javaEE规范中,都有对XA模式的支持。比如,如果你看到一些jar包里部分package是以XA开头的,就是对两阶段XA事务的支持。虽然基本不会使用。
两阶段提交带来的问题:
一,全局锁LOCK掉整个大事务,性能低下,全局锁带来了极大的风险。
二,网络是不可靠的,在两阶段任务一个阶段,如果出现网络问题,则都会导致系统出现异常。
三,侵入业务比较多,比如编程需要实现XA协议等。
因此,这样的分布式事务解决方案,不仅侵入业务,而且也没有解决实质性问题,不适合使用。
现在,互联网应用的数据一致性核心解决方案,都是:补偿。
分布式解决方案-理论基础
在互联网微服务方案中,存在CAP定理和BASE理论:
BASE理论简单可以总结如下方案:
BA:Basic Availability 基本业务可用性。
S : Soft state 软状态 允许数据短时间不同步。异步
E:Eventual consistency 最终一致性(数据最终都是一致的,你不能要求实时一致性,如果产品经理要求实时一致性,就把产品经理打屎!)
基于BASE理论:产生如下柔性事务解决方案:
可查询操作
幂等操作
TCC操作
可补偿操作
可查询操作:多用于分布式解决方案-最大努力通知型解决方案:(不同公司的系统):
比如说淘宝异步通知,只通知一定次数,通知完还收不到响应我就不通知了。但是淘宝要提供查询订单状态结果的接口,当业务方状态异常的时候来查询。这就是可查询。
幂等:网络是不可靠的,在收不到ACK的情况下,接口可能会被重复调用,因此接口要幂等。一笔订单调用多次和调用一次结局一样。
TCC和可补偿是下文要将的。分布式事务的关键就是补偿。
分布式解决方案-TCC
TCC解决方案是目前分布式事务常用解决方案之一。也是笔者近期将要实现的一个分布式事务框架rpc-tcc-transaction(敬请关注)。
TCC解决方案要求业务接口每一个业务都写三个接口:tryX,confirmX,cancelX。
try:各个业务接口预留业务资源。
confirm:try阶段没有问题,执行confirm。
cancel:try阶段发生问题,执行cancel。
成功的事务删除日志。
事务恢复:定时线程根据事务日志获取执行结果恢复事务(补偿的方式。)
和XA事务相比,优点:
1)不锁整个数据库,每个接口都是独立的事务。
2)通过补偿实现最终一致性。
3)在足够优化后性能较为可靠。
4)可以实现与业务和具体RPC框架不耦合。
缺点:
1)性能有些损耗。
2)开发成本提升。
3)业务自行实现幂等。
分布式事务解决方案-可靠消息最终一致性
可靠消息最终一致性是最常用的一致性解决方案。
他适合实时性不那么高的一致性场景。如对账,统计。笔者今年年底要实现可靠消息最终一致性分布式事务框架message-transaction。(敬请关注)
正向流程是这样的:
是不是很简单。但是网络是不可靠的,我们还需要逆向流程做事务补偿。
逆向流程:
上面的流程,1,2,3,4,5,6,7,都是有可能会出现问题的。
需要逆向流程:
1,消息确认,待确认的消息到底主动方到底有没有主动执行成功?
2,消息消费,长时间未消费的投递重新消费。
上面的架构看似有些和业务耦合?实际上有2个优化点:
1,与业务方1的耦合可以做标准消息服务接口和标准消息会调接口,形成规范。
2,与业务方2的耦合可以在业务方2之前挂载一个通用代理。
总结
作为一个程序员,不断思考总结行业技术痛点,才能有所进步。
上面的分布式事务解决方案不是我凭空杜撰的,而都是有相关的理论依据。
我写的分布式事务框架,可能将来在工作中,在遇到事务问题,可以直接提供解决方案,降低开发成本,保障业务强大的容错性。对于一个程序员来说,这是最具有幸福感的事情了。
欢迎留言分享自己的思考。
(完)
chen陈序猿|一起学技术吧
以上是关于分布式事务那些事的主要内容,如果未能解决你的问题,请参考以下文章
RocketMQ——Transaction Message(事务消息)