技术控 | 关于分布式事务的思考 这才是正确逻辑
Posted 金融IT圈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了技术控 | 关于分布式事务的思考 这才是正确逻辑相关的知识,希望对你有一定的参考价值。
众所周知,神州信息的银行分布式核心系统在业内是名声远扬的,分布式技术对银行的核心业务进行了颠覆性重构,使银行业务处理与会计核算功能相分离。提起强大到无敌的分布式系统,就不得不提背后做支撑的分布式事务。
本篇文章由神州信息金融业务产品技术专家薛春雨老师分享,期望对您的技术操作技巧有所启发和帮助,欢迎留言交流。
所谓事务,简单而言就是一组操作同进同退(All or Nothing),对大多数开发人员而言,马上就会跟对数据库的操作联系在一起,例如,将几个对数据表的操作放在一个事务中,如果执行成功就全部提交,如果有一个失败就全部回滚。很多人每天都在进行着这样的操作,但对其背后的理论支撑却知之甚少。
ACID
在传统的集中式系统中的事务有四个非常显著的特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation) 和持久性(Durability)。
原子性(Atomicity):所谓原子也就常规意义上说的最小单位,这里的原子性也就是强调其的不可分割性,最终的体现也就是“All or Nothing”。这个特性也可以理解为事务的目标。
一致性(Consistency):一致性强调的是一个事务执行之前和执行之后都必须处于一致性状态。很多人将“一致性”跟上面的“原子性”混为一谈,其实这个特性更多想表达的是一致性的程度,造成这种混淆的原因更多的是因为大部分人都是面向单个数据库来谈事务的,只要启动数据库的本地事务机制就可以保证事务的一致性,但其实在数据库执行过程中出现宕机的情况下也是有可能不一致的;所以可以简单的理解“原子性”是理想,“一致性”是现实。
隔离性(Isolation):一个事务的执行不能被其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。这个特征其实是非常重要的,但经常被大家所忽略,因为其更多的是数据库自身来保证的。大家可以试想一下,如果没有隔离性的话,我们所谓的事务就无从谈起,因为数据本身就是乱的。
持久性(Durability):指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。也就是说不能反悔。
传统的基于单个数据库操作的事务跟ACID理论是非常吻合的,对使用者来说甚至感知不到它的存在,因为大部分事情都是数据库帮我们做了,持久性(Durability)和隔离性(Isolation)是数据库首先保证的,甚至对隔离性数据库还提供了不同的隔离级别;另外,只要我们合理的使用数据库的事务操作方法,也基本可以保证一致性(Consistency);原子性(Atomicity)作为目标实际是通过一致性(Consistency)的保证度来体现的。
挑战的根源
在集中式系统下一般关注的资源就只有一个数据库,但在分布式系统中,涉及的资源不仅种类比较多,并且同一种类的资源的数量也会有多个:
例如:有些涉及数据层进行分布的系统,首先就会面临多个数据库;有些业务还要产生跨系统的服务调用,但还要保证事务的一致性;甚至有些服务内部还会操作JMS或者文件等。按照事务的原子性(Atomicity)要求,在发生局部失败的时候,对相关资源的变化都是需要回退的。
可以很明确的看到分布式跟传统集中式在事务上的最大区别就是面对多个资源,并且不同的资源在物理上是完全独立的。之前一个数据库中的各种操作,由于物理上是在一个数据库中,所以其保持“同进同退”具有天然的条件(当然数据库帮我们做了很多事情),而在分布式的背景下,如果还按照传统的思维显然是不合理的。之前很多数据库帮我们做的事情就需要我们自己来做,只是在更高的层面来实现,其复杂度是肯定要提升的,所以,所有参与人员必须对其有正确的认识,如果还想跟传统集中式一样的简单其实是不现实的。
强一致是否是必须的?
通过上面的分析,我们可以发现分布式系统事务面临最大的挑战是:
1.多个资源物理是分开的;
2.资源之间没有关联;
所以要完全做到事务的绝对一致几乎是不可能的,只可能尽可能的提升其保证度,不同的机制在保证度上是有差别的。我们再看一下分布式下ACID的区别:
A:作为目标,是不会发生变化的,只是达到的难度提升了;
C:作为最终的一致性保证度的体现,跟具体的机制有关,最终的差别将是几个9的区别;
I:隔离性在传统集中式的事务中我们不是特别关注,但在分布式的背景下,由于各个物理资源相互独立,对其的隔离性的保证就提出了很高的要求,如果没有有效的手段保证隔离性的话,在出现异常的情况下,即使要恢复都会因为不具备条件而无法进行。这也是为什么数据库中有很多种不同的锁,其就是数据库内部保证隔离性的机制体现。
D:对于资源的持久性,基本没有太大的区别。
从上面我们可以看出,分布式下事务的复杂度是比较高的,再像之前传统集中式那样强调事务的强一致性其实是不现实的,其实传统的集中式系统也并不一定就是完全的强一致,例如:在事务提交过程中数据库宕掉的极端情况下,有可能事务就不一致;还有,银行的核心系统中都有日终的对账机制,我们反过来想为什么会有这个机制,因为有可能日间的交易出现账务不一致的情况,需要在日终通过其他手段去平账,这其实是用事实证明了银行是可以接受一定程度的不一致的,只要最后你让我一致就可以,这其实就是最终一致性(并且期间隔离性还是没法保证的,也就是日终平账还有可能平不回来)。只是我们平时习惯了单个数据库的事务处理,而给自己画了一个无形的圈而已。
BASE理论
分布式背景下,因为需要操作的资源的变化,我们对事务的应对策略也需要与时俱进,在传统的ACID之外,还有一个理论叫BASE理论:
基本可用(Basically Available):指分布式系统在出现不可预知故障时,允许损失部分可用性,如响应时间上的损失或功能上的损失。
软状态(Soft-state):指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性。
最终一致性(Eventual consistency):最终能够达到一个一致的状态,而不需要实时保证系统数据的强一致性。
可以看出这个理论的核心思想是:结合了分布式的特性,强调了分布式的高可用,同时也兼顾了事务的一致性。也就是在出现故障时,只有故障影响的部分不可用,其他部分还可以正常提供服务;对出现故障的部分,通过中间状态等的记录(留痕),在条件具备时,可以达到最终一致。上述3点都是非常重要的,不能割裂的来看待。
其实我们可以认为ACID和BASE是两种不同的设计理念,两种理念适合的场景也是有区别的,在分布式的背景下,我们更建议以BASE为主,在涉及一个资源的内部再使用ACID,使两种理念有机的结合。
应对策略
结合分布式的实际情况(忽略事实上的差异无异于掩耳盗铃)及BASE理论,我们建议分布式背景下的事务控制,至少需要有以下一些大的原则需要重点考虑:
分布式下的事务是有代价的,尽量减少分布式事务的发生;
不能只从数据库的角度来考虑问题,必须进行更高层面的抽象;
需重点从隔离性和一致性保证度两个方面来考虑;
为保证隔离性必须进行资源的锁定,粒度尽可能的小,以减少影响范围;
机制上需要规避逻辑上的集中点,否则会有单点风险,并且跟分布式本身的理念也违背;
需要多种手段配合达到一个平衡,很难一种机制通吃所有场景。
在上述大的原则下,具体的分布式事务控制机制,需要从如下几个维度综合考虑,而不是简单的从自己的熟悉程度甚至个人的喜好来定:
1. 隔离性:隔离性是首先要保证的,在谈事务的时候,如果没有隔离性,数据就会相互影响,极端情况下造成不可控;
2. 保证度:在隔离性的前提下,尽可能的提升一致性的保证度;
3. 风险:本身的机制不能存在明显的隐患,就像上面说的类似逻辑上的单点,否则其出现故障,对整体的事务都会造成影响;
4. 代价:为了达到上述目标,付出一定的代价是应该的(更多的是取舍),但如果代价是不可承受的话,其机制也不具备可操作性;
5. 复杂度:同样从给业务带来的复杂度来看,也需要控制在一个合理的范围内,否则业务变得非常复杂,也不具备可操作性。
前进还是后退?
在传统集中式的事务处理机制中,当部分出现失败,我们通常会选择将前面的全部回滚,基于一个数据库的回滚是很容易控制的,但在分布式的背景下,如果参与的资源比较多,如果要全部回滚成功,跟正向提交面临同样的问题,也就是回滚的过程中,各种资源的异常情况的组合将是一个巨大的挑战,当出现部分回滚成功,部分失败的情况,很多时候业务人员已经完全搞不清楚该怎么操作了,并且随着参与资源的数量的增加,组合的种类将成指数上升,把所有的组合都搞清楚几乎是不可能的。
所以,我们建议不用把所有逆向的异常情况组合搞清楚,而只需要关注正向情况即可,也就是出现异常情况,我们不回滚,而是等异常解除后通过机制(可通过执行过程中留痕的方式)促使其成功(当然在期间保证其隔离性,这点很关键)。这种思路,不仅跟BASE理论不谋而合,其实更是不得已的选择。
上述的建议方案,从上面的5个维度进行分析:隔离性是可以保证的;保证度很高;风险很低;由于在过程中需要留痕,对性能还是有所影响的,也就是有一定的代价;业务只要按照规范进行开发即可,复杂度可控。
没有所谓的“银弹”
不同的事务处理机制在上述5个维度有自己的不同体现,当然也有自己适合的场景,所以,我们建议根据不同的业务场景选择合适的机制,对所选择的机制覆盖不了的情况可以考虑从业务的角度进行补充,以综合达到一个可以接受的程度就是一个好的解决方案,没有所谓的一个“银弹”可以解决所有问题。
具体到银行的核心系统,我们建议将保证度比较高的机制用于跟账务相关的服务;但对一些不是特别重要的服务或者一些长尾服务可以考虑采用服务组合的模式,通过冲正机制进行处理,即使出现这个层面的不一致也影响不大;甚至一些粒度比较大的服务,整体采用服务组合模式,其内部的个别重要的原子服务采用类似上述的“促使成功”的机制也是可以考虑的。
免责声明
点击下列 关键词 即可查看往期内容
丨丨丨
丨丨丨
丨
金融IT圈 微信ID:JinrongIT
长按识别二维码即可关注
以上是关于技术控 | 关于分布式事务的思考 这才是正确逻辑的主要内容,如果未能解决你的问题,请参考以下文章
求求你们别再用 kill -9 了,这才是 Spring Boot 停机的正确方式!!!