天天看点

分布式事务云市场分析

全局事务服务gts上个月开始在阿里云上公测,之前我们也发表了一篇「破解世界性技术难题!gts让分布式事务简单高效」的文章,引起了业界广泛关注,接受了大量的咨询,故希望通过本文让大家对gts有更深入的理解。

gts在目前在阿里内外部已经有较大规模的应用,有100多个用户,其中专有云大用户就有10多个,预计今年将有更大规模的市场需求爆发。

<a></a>

分布式事务解决的用户最本质诉求是什么?数据一致。

大中企业有一个共同的诉求是数据一致,几乎覆盖到各个行业。

比如说零售行业,库存与出货的数据需要保持一致,出货量与库存数据不匹配,显而易见会出问题,拿到订单却没货了,或者有货却下不了订单。

比如说金融行业,转账数据搞错了,a扣款了,b没加上,马上该用户投诉了;a没扣款,b却加上了,产生资损;又比如从总账户中买了基金、股票后余额不对了,等等,都会导致严重问题。

比如说车票购票网,用户退票了,但是他买的那个座位状态还是“已售卖”,造成损失;用户购买了,却已经没座了,更是大问题。

数据一致对各个行业都很重要,但为什么以前不觉着是个普遍需求?

以前多数企业的数据规模、业务复杂度相对较小,很多操作可以单机完成,数据库本地事务可以搞定,所以数据一致问题不那么明显。

随着互联网技术快速发展,数据规模增大,分布式系统越来越普及,采用分布式数据库或者跨多个数据库的应用在中大规模企业普遍存在,服务化也是广泛应用,由于网络的不可靠和机器不可靠,数据不一致问题很容易出现。

数据一致性问题是必须解决的,在很多大企业多年前就已经成为突出问题,他们是怎么解决的?有这么几个典型方案:

• a)xa事务方案

• b)柔性事务

• c)基于消息的最终一致

• d)业务补偿与人工订正

方案a,xa协议由tuxedo首先提出的,并交给x/open组织,作为资源管理器(数据库)与事务管理器的接口标准。oracle、informix、db2和sybase等各大数据库厂家都提供对xa的支持。xa协议采用两阶段提交方式来管理分布式事务。最主要缺点是性能差,容易成为业务发展瓶颈,所以国内很少用户采用。优点是满足事务acid,有几个很成熟的产品,比较稳定,典型的是oracle tuxedo 和 ibm cics。但是前景不看好,这么多年缺乏重要技术突破,性能上不去,怎么拥抱互联网。

方案b,柔性事务(遵循base理论)是指相对于acid刚性事务而言的,常见的是tcc型事务(try/confirm/cancel)。最主要缺点是业务侵入性太强,需要大量开发工作进行业务改造,给业务升级、运维都带来困难。优点是业务开发人员可以灵活控制事务逻辑,达到很好性能。在蚂蚁金服有广泛使用。以我的理解,这适合特定领域,很难作为通用方案对外大面积铺开。

方案c,常用办法是通过本地消息表完成,也有一些通过事务消息。主要缺点同样是业务侵入强,需要大量额外开发工作,给业务升级、运维都带来困难。还有一个问题是使用场景受限,有些最终一致无法满足的情况,需要人工干预。优点是扩展性好,可以满足日益扩大的业务,相对b来说开发没那么复杂。这是比较主流的方案,在阿里广泛使用。

方案d,多熟中小企业靠业务补偿与人工订正解决。缺点是运维、支持投入人力大,优点是简单直接,逻辑不复杂。在业务量不大的情况下能hold住,但业务扩大了就很难应付。

这些问题很明显,为什么没有产品解决?因为技术层面很难,缺乏关键创新,这已经是至少10多年的世界性难题了。这种情况下,gts横空出世,通过一系列技术创新,希望能彻底解决这些问题。

从上面分析可以看出,方案b/c/d是因为a的性能满足不了业务需求的无奈之举。

做出一个同样满足事务acid的强一致的通用分布式事务中间件,并且性能足够,简单易用,才是终极方案,这就是gts的出发点。gts产品可以通过技术创新,解决上述方案分析中b、c和d用户的问题,而不是寻求作为方案a用户的替代产品。

事务比较抽象,我举个例子类比下gts给用户带来了哪些改变。

你每天上班,要经过一条10公里的只有两条车道的马路到达公司。这条路很堵,经常需要两三个小时,上班时间没有保证,这是方案a的问题。

选择一条很绕,长30公里但很少堵车的路,这是选b。上班时间有保证,但是必须早起,付出足够的时间和汽油。

选择一条有点绕,长20公里的山路,路不平,只有suv可以走,这是选c。上面分析了c方案场景受限,对应于交通,是底盘低的小轿车没法开,车型受限。

发扬艰苦奋斗,走路上班,这是选d。

gts做的是什么?修了一条拥有4条车道的高架桥,没有绕路,还是10公里。不堵车,对事务来说是高性能;不绕路,对事务来说是简单易用,对业务无侵入,不用为事务而重构;没有车型限制,对事务来说是没有功能限制,提供强一致事务。在没有高架桥的时代,高架桥出现对交通来说就是一个颠覆性创新,很多以前看来无解的问题就迎刃而解了,同样的,gts希望通过创新改变数据一致性处理的行业现状。

通过这个类比相信大家对gts可以给用户带来的价值会有一定的了解。

下面我们列出几个关键问题跟大家探讨下。

1)gts是强一致,还是最终一致?

2)gts默认隔离级别是“读未提交”,对业务影响大吗?

3)gts什么场景下不能保证数据严格一致?

gts是强一致,不是最终一致。一致性和隔离性对多数用户不好区分,一致性对应事务acid的“c”,隔离性对应的是“i”。

所谓强一致,在于用户发起事务提交或事务回滚得到确认后,数据已经是一致的。而最终一致,用户发起提交,得到响应说提交成功了,但是未必真的成功,只是说过段时间它最终会数据一致。以转账为例,转成功了你就一定立即可以查到是强一致,最终一致没有这种保证。

强一致这个概念有很多争论,不同人有不同理解,没有权威定义。我们不搞学术化,大家理解实际业务中一致性是什么样子就好了。

隔离性与强一致没有必然联系。比如说把oracle的隔离级别设置为读未提交,这时oracle就不强一致了?显然还是强一致。有人提出串行化的隔离级别才是强一致,那我想问,在生产系统你会把数据库隔离级别设置成串行化吗?显然绝大多数不会,这样理解的话,大家就别搞强一致了。

gts支持两种隔离级别,“读未提交”和“读已提交”。“读未提交”比“读已提交”有明显性能优势,而且适合绝大多数场景,所以作为我们默认隔离级别。

提起“读未提交”,大家第一反应是有脏读,会影响业务。真正分析下业务,会发现“读未提交”与“读已提交”的差别对业务有实际影响的场景很少。更多的场景是,如果你的业务逻辑在“读未提交”下有问题,在“读已提交”下同样存在问题;反之,“读已提交”下没有问题,在“读未提交”下也很少会存在问题。

还拿通俗易懂的转账为例。假定a、b、c账户各有10000元,账户信息在不同的数据库,有两个并发事务,事务1 a-&gt;b 1000元,事务2 a-&gt;c 2000元。转账的业务逻辑是,先查出账户余额,再根据转账数目算出一个新余额来,然后用这个新余额去做update。

在“读未提交”情况下,事务1在进行中,事务2读到了a的账户9000元,恰巧这时事务1发生故障回滚了,两个事务都完成后a 7000,b 10000,c 12000。数据不一致少了1000(a+b+c=29000),看来脏读不靠谱,但是再分析下,上面的逻辑在读已提交下,是否也存在问题?

在“读已提交”情况下,事务1在进行中,事务2读到了a的账户10000元,两个事务都成功完成后a 8000,b 11000,c 12000。数据不一致多出1000(a+b+c=31000),看来也不靠谱啊。

问题根源在于上面的应用逻辑有典型的并发处理不当,修改办法很多,比如用select … for update 查询余额,可以锁定数据防止并发修改,或者是用sql中的逻辑运算代替,如 update … set value=value-2000。

我们追求极致性能,引导用户用“读未提交”的思路来写分布式的业务逻辑,让绝大多数sql得到更好性能,个别sql必须用“读已提交”时才用。这比默认就用“读已提交”更加合理。

当用户用gts事务操作数据,同时并发用非gts方式(比如用oracle sqlplus)更改同一行数据,会影响到数据一致性。这种情况下,gts校验发现数据被修改了,会发出告警到用户和我们团队,用户可以通过我们提供的工具进行订正(通常是点点按钮就ok了)。

问题的根本在于,gts阻止不了别的方式写数据。所以,我们建议用户需要用gts操作的数据,做到用且仅用gts,混着搞是不安全的。我想这种限制是合理的(别的方案也有类似限制,按规则出牌),已有用户都能接受。

在个别需要混用的特殊场景下,可以选择gts和非gts有个时间差的方式。比如有个用户是这样的,通过gts处理订单,另有一个不走gts的定时任务负责清理完成的订单。我们建议用户的定时任务加个where条件只处理3分钟前的订单,这样就很安全了,因为业务中设置的gts超时时长为1分钟,定时任务清理不会影响进行中的事务。

可以看到,很简单的业务逻辑就可以避免这种问题,做少量改造换来大幅性能提升是值得的。

下一篇: 学习