分布式系统一致性保障方案Word格式文档下载.docx
- 文档编号:20084898
- 上传时间:2023-01-16
- 格式:DOCX
- 页数:8
- 大小:171.07KB
分布式系统一致性保障方案Word格式文档下载.docx
《分布式系统一致性保障方案Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《分布式系统一致性保障方案Word格式文档下载.docx(8页珍藏版)》请在冰豆网上搜索。
本文重点来阐述下关于一致性的方案,包括强一致性和最终一致性。
而在互联网领域,很多情况下都是牺牲强一致性,来达到高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。
数据库本地事务
数据库事务肯定是强一致性的方案,而且是一致性最简单的方案,因为一致性是数据库的事务来保证的,业务层不需要关心细节。
比较典型的应用是在返现场景下,针对带有返现的交易的退款,需要一次性退两笔交易单,采用的就是通过数据库本地事务来完成的。
具体如下:
用户A花了100元购买商户B的商品,购买结束后返现给用户A2元。
这是两笔交易,原始交易是100元,返现交易是2元。
那么发生退款时,需要保证两笔交易同时都退款。
这个就是直接采用数据库本地事务实现的,即一次退款请求,两笔交易同时退款。
总结:
数据库事务的优点是简单,业务层关心的很少。
但是对于一个可用性很高的系统来说,所有的业务都揉在数据库事务执行,会让事务非常的复杂,不利于系统的扩展和维护。
两阶段提交
除了数据库能够保证本地的一致性,对于互联网系统来说,更多是分布式系统。
提到分布式系统,必然提到分布式事务。
而分布式事务中,就不得不介绍两阶段提交协议(2pc)。
而在核心系统,两阶段提交的方案主要应用在分布式数据库NesioDB和交易账务分离的柔性事务中。
分布式数据库NesioDB是由XXDBA和XX钱包联合开发的,支持分布式事务的数据库,目前已经应用在XX钱包的核心交易业务上,并稳定运行两年。
该数据库的设计要求是让使用者能够像使用单机数据库一样的使用分布式数据库,因此实现的分布式事务,满足单机事务的ACID原则。
关于分布式事务的一致性,采用的就是两阶段提交的方式来实现的,并且满足分布式事务模型。
如下图所示。
第一阶段是准备阶段。
DTM通知所有参与事务的各个RM,给每个RM发送prepare消息。
RM接收到消息后进入准备阶段后,要么直接返回失败,要么创建并执行本地事务,写本地事务日志(redo和undo日志),但是不提交(此处只保留最后一步耗时最少的提交操作给第二阶段执行)。
第二阶段是提交/回滚阶段。
DTM收到RM准备阶段的失败消息或者获取RM返回消息超时,则直接给RM发送回滚(rollback)消息,否则发送提交(commit)消息。
RM根据TM的指令执行提交或者回滚,执行完成后释放所有事务处理过程中使用的锁(最后阶段释放锁)。
数据库层面的两阶段提交,可以用来保证分布式事务的一致性,使得使用者使用分布式事务和单机事务一样方便。
而两阶段提交的另外一种实现,即TCC(Try-Confirm-Cancel),也就是业务层面的柔性事务。
交易和账务分离的一致性实现,就是采用这种柔性事务来完成的。
首先来说说柔性事务,它涉及3个模块,主业务、从业务和活动管理器(协作者)。
下面这张图是有关柔性事务一张经典的图。
第一阶段:
主业务服务分别调用所有从业务服务的try操作,并在活动管理器中记录所有从业务服务。
当所有从业务服务try成功或者某个从业务服务try失败时,进入第二阶段。
第二阶段:
活动管理器根据第一阶段从业务服务的try结果来执行confirm或cancel操作。
如果第一阶段所有从业务服务都try成功,则协作者调用所有从业务服务的confirm操作,否则,调用所有从业务服务的cancel操作。
在第二阶段中,confirm和cancel同样存在失败情况,所以需要对这两种情况做异常处理以保证数据一致性。
1.Confirm失败:
则回滚所有confirm操作并执行cancel操作。
2.Cancel失败:
从业务服务需要提供自动cancel机制,以保证cancel成功。
如果对应到交易和账务分离的项目中,流程如下:
主业务服务调用交易和账务执行try的操作,交易开启事务,做业务上的判断和写入,但是不提交事务。
账务层面做资源的锁定。
账务资源锁定成功,交易提交事务成功,然后发送confirm给账务。
如果交易提交失败,则发送cancel对资源进行释放。
如果在confirm或者cancel出现异常情况下,同样需要对异常进行处理来保证数据一致性。
这种方式实现难度不算太高,比较适合传统的单体应用,在同一个方法中存在跨库操作的情况。
回滚机制
在分布式架构中,功能X,需要去协调后端的A、B甚至更多的原子服务。
那么问题来了,假如A和B其中一个调用失败了,那可怎么办呢?
这个时候,可以用回滚机制来保证一致性。
该机制应用在钱包配合信贷做的联合放贷项目中。
该项目中总共有两个原子操作,如下图所示。
两个原子操作,分别是资金归集和资金到卡。
所谓资金归集,是将商户A的钱和商户B的钱归集到中间商户C。
而资金到卡,是将中间商户C的钱,通过银行系统打入到D用户的银行卡。
这两个操作要满足一致性,即资金归集成功,然后打款到用户的卡成功。
或者是商户A和B的钱没变化,资金到卡失败。
总而言之,是不允许资金停留在中间商户C的。
针对这种情况,通过回滚机制,提供一个强大的回滚操作来实现上述的一致性。
比如资金归集成功,而资金到卡失败,那么对归集的资金操作做回滚处理,也就是资金从中间商户C分别回到商户A和B中。
这种方式缺点比较多,通常在复杂场景下是不推荐使用的,除非是非常简单的场景,非常容易提供回滚,而且依赖的服务也非常少的情况。
这种实现方式会造成代码量庞大,耦合性高。
而且非常有局限性,因为有很多的业务是无法很简单的实现回滚的,如果串行的服务很多,回滚的成本实在太高。
本地消息表
这种实现方式的思路,其实是源于ebay,后来通过支付宝等公司的布道,在业内广泛使用。
其基本的设计思想是将远程分布式事务拆分成一系列的本地事务。
如果不考虑性能及设计优雅,借助关系型数据库中的表即可实现。
本地消息的方式,在应用在钱包非核心业务异步化改造项目中。
该项目当时改造的方案如下:
1.核心业务实时写入交易表
2.非核心业务非实时异步写入交易表按照用户维度的交易查询表。
交易表是交易维度的,而为了满足用户的查询性能,需要备份复制相同的按照用户维度的交易查询表。
从业务属性上来看,交易表是核心业务,交易查询表是非核心业务(查询使用)。
而实现上,交易表是核心数据库,而查询表则属于非核心数据库。
但是,这两者需要满足一致性。
关于这类一致性保障,如果有不丢消息的消息队列,则很容易解决。
万一没有这类消息队列呢?
其实,使用本地消息表,也一样可以解决。
如图所示,是利用本地消息表保持最终一致性的应用。
具体如下:
1.业务A将本地消息和A业务数据以本地事务的方式写入DB1;
2.业务A写完本地事务后,发送消息给MQ。
3.MQ推送消息给业务B,业务B执行消息,写入DB2.
4.由于MQ不能保证消息不丢,如果消息丢失了,则需要通过业务C,读取DB1的消息,然后rpc发送给业务B重新执行。
当然,如何判断DB1的消息已经消费,这个可以通过DB2的事务执行结果来判断。
上诉的方式是一种非常经典的实现,基本避免了分布式事务,实现了“最终一致性”。
但是,关系型数据库的吞吐量和性能方面存在瓶颈,频繁的读写消息会给数据库造成压力。
所以,在真正的高并发场景下,该方案也会有瓶颈和限制的。
补偿机制
补偿机制在分布式系统中,应用最为广泛。
在钱包应用的场景比较多,比如核心收银台和付款到卡。
核心收银台中,当请求银行扣款,扣款成功后,自身系统挂掉了。
这个时候就会有一个后台程序,我们也称作补单程序来开始处理这类流程,让原来中间断掉的流程继续走下去。
一般成熟的系统中,对于级别较高的服务和接口,整体的可用性通常都会很高。
如果有些业务由于瞬时的网络故障或调用超时等问题,那么这种补偿机制其实是非常有效的。
总结
本文通过核心系统的几个具体实际项目,阐述了如何保证分布式系统的一致性。
每一种方案都有一定的特征和应用场景。
其实分布式系统的事务一致性本身是一个技术难题,目前没有一种很简单很完美的方案能够应对所有场景。
具体还是要使用者根据不同的业务场景去抉择。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 分布式 系统 一致性 保障 方案