分布式系统一致性保障方案总结

标签: | 发表时间:2017-09-21 03:43 | 作者:
分享到:
出处:https://mp.weixin.qq.com

猫友会群里经常卧虎藏龙,转载一篇百度大牛,投稿原创文章,大家交流学习 ,文末有作者个人公众号。欢迎更多猫友投稿,发布原创文章和干货和大家分享交流。





引言

       在互联网系统中,理想的情况下,肯定是希望系统能够同时满足“一致性”、“可用性”和“分区容忍性”。 但是基于熟悉的CAP定律也好,还是BASE理论, 我们知道,在实际情况中是不可能实现的。而在金融领域,一致性是最为关注的特性,任何情况下都必须满足一致性。关于CAP定律和BASE理论,本文不再介绍,有兴趣的同学可以自行百度一下。本文重点来阐述下关于一致性的方案,包括强一致性和最终一致性。 而在互联网领域, 很多情况下都是牺牲强一致性,来达到高可用性,统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。



数据库本地事务

       数据库事务肯定是强一致性的方案,而且是一致性最简单的方案,因为一致性是数据库的事务来保证的,业务层不需要关心细节。比较典型的应用是在返现场景下,针对带有返现的交易的退款,需要一次性退两笔交易单,采用的就是通过数据库本地事务来完成的。具体如下:

用户A花了100元购买商户B的商品,购买结束后返现给用户A 2元。 这是两笔交易,原始交易是100元,返现交易是2元。 那么发生退款时,需要保证两笔交易同时都退款。这个就是直接采用数据库本地事务实现的,即一次退款请求,两笔交易同时退款。



总结: 数据库事务的优点是简单,业务层关心的很少。但是对于一个可用性很高的系统来说,所有的业务都揉在数据库事务执行,会让事务非常的复杂,不利于系统的扩展和维护。



两阶段提交

        除了数据库能够保证本地的一致性,对于互联网系统来说,更多是分布式系统。提到分布式系统,必然提到分布式事务。而分布式事务中,就不得不介绍两阶段提交协议(2pc)。 而在核心系统,两阶段提交的方案主要应用在分布式数据库NesioDB和交易账务分离的柔性事务中

       分布式数据库NesioDB是由百度DBA和百度钱包联合开发的,支持分布式事务的数据库,目前已经应用在百度钱包的核心交易业务上,并稳定运行两年。该数据库的设计要求是让使用者能够像使用单机数据库一样的使用分布式数据库,因此实现的分布式事务,满足单机事务的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的事务执行结果来判断。



总结: 上诉的方式是一种非常经典的实现,基本避免了分布式事务,实现了“最终一致性”。但是,关系型数据库的吞吐量和性能方面存在瓶颈,频繁的读写消息会给数据库造成压力。所以,在真正的高并发场景下,该方案也会有瓶颈和限制的。



补偿机制

       补偿机制在分布式系统中,应用最为广泛。在钱包应用的场景比较多,比如核心收银台和付款到卡。 核心收银台中,当请求银行扣款,扣款成功后,自身系统挂掉了。这个时候就会有一个后台程序,我们也称作补单程序来开始处理这类流程,让原来中间断掉的流程继续走下去。

      一般成熟的系统中,对于级别较高的服务和接口,整体的可用性通常都会很高。如果有些业务由于瞬时的网络故障或调用超时等问题,那么这种补偿机制其实是非常有效的。



总结

       本文通过核心系统的几个具体实际项目,阐述了如何保证分布式系统的一致性。每一种方案都有一定的特征和应用场景。 其实分布式系统的事务一致性本身是一个技术难题,目前没有一种很简单很完美的方案能够应对所有场景。具体还是要使用者根据不同的业务场景去抉择。




相关 [系统 总结] 推荐:

系统性能调优吐血总结分享:原创

- crystal - 博客园-首页原创精华区
首先是较为精准的定位问题,借助于相应的工具包,分析系统性能瓶颈在哪,在根据其性能指标,以及所处于层级决定选择优化的方式方法. 在选择优化的方式方法时,大家可以参照以下章节调优方法,架构优化递进,进行正确的,有针对性,有步骤的优化. 可能会发现部分指导思想或许有相悖嫌疑,大可不必较真,系统优化的过程本身就是一个不断分离+共享的组合拳,至于具体选择哪种优化方式,根据具体需求来定,但大型应用发展的总体思路是不断分离,在通过索引(非数据库)进行关联起来,.

(总结)Linux系统初始化优化Shell脚本

- 疯癫二楞子 - 服务器运维与网站架构|Linux运维|互联网研究
PS:本Shell脚本主要用于新安装Linux服务器系统的初始化工作,具体包括关闭ipv6模块、关闭selinux、让vim显示颜色、设置系统语言编码、优化系统服务、内核参数优化等. 可以根据自己的实际情况修改,可用于生产环境. 原作者是NetSeek,本人做了部分修改. cpuspeed | crond | irqbalance | microcode_ctl | mysqld | network | nginx | php-fpm | sendmail | sshd | syslog ).

2013-11-9 做的一次系统宕机诊断及总结

- - CSDN博客数据库推荐文章
        首先交代一下系统的基本情况,开发是J2EE架构,最流行的那种,部署架构是weblogic+oracle. 2013-11-11接到现场实施人员反馈在9日上午(周六)有宕机并发回了weblogic的server.log.         在 08时25分49秒和 09时28分31秒之间有四次导出,造成了最终的内存溢出.

搭建网页滤重系统的工作总结

- - _不是我干的 _
趁最近工作业务不多,写篇博客关于 【搭建一个基于 网页相似度来 滤重的系统服务】 的相关工作. 我接手时的线上代码主要有如下特点:. 旧代码的滤重效果和预期的不一致,而旧代码的作者已经离职,所以旧代码等于一个无人可以解释的黑盒. 只知道有问题,但是出了问题没人知道如何解决. 性能低下得无法容忍,由于线上出现问题没人知道如何修复,解决的办法只有重启.

Mysql Tomcat C3p0 系统性能调优个人总结

- - CSDN博客数据库推荐文章
应用逻辑 就是用c3p0 到数据库查询数据并http返回Json数据. 1 调优前的最初的测试结果   JMeter test result. 这个数据是从程序的log 中打印出的 数据库select语句 中得出的结果(正确与否后面会有讨论). 2 经过IOD系统打印 SQL query 的执行时间 和 tomcat 每个request 的 响应时间,找出 系统瓶颈 是因为一个 select语句 使用了 in:.

分布式系统常用思想和技术总结

- - 企业架构 - ITeye博客
分布式系统常用思想和技术总结. 分布式系统比起单机系统存在哪些难点呢. 由于服务和数据分布在不同的机器上,每次交互都需要跨机器运行,这带来如下几个问题:. 同机房的网络IO还是比较块的,但是跨机房,尤其是跨IDC,网络IO就成为不可忽视的性能瓶颈了. 并且,延迟不是带宽,带宽可以随便增加,千兆网卡换成万兆,只是成本的问题,但延迟是物理限制,基本不可能降低.

分布式系统一致性保障方案总结

- -
猫友会群里经常卧虎藏龙,转载一篇百度大牛,投稿原创文章,大家交流学习 ,文末有作者个人公众号. 欢迎更多猫友投稿,发布原创文章和干货和大家分享交流.        在互联网系统中,理想的情况下,肯定是希望系统能够同时满足“一致性”、“可用性”和“分区容忍性”. 但是基于熟悉的CAP定律也好,还是BASE理论, 我们知道,在实际情况中是不可能实现的.

一线DBA总结:MySQL搭配XFS文件系统优势最大

- - MySQLOPS 数据库与运维自动化技术分享
来自国外问答SNS网站Quora的一个问题:XFS、ZFS和ext3这3个文件系统哪个能够与MySQL产生最佳的性能?对此,来自Facebook的资深数据库专家Domas Mituzas给出了自己的解答,他认为MySQL最适合XFS文件系统. 在XFS文件系统的Linux版本发布之前,选择适合的Linux文件系统很简单,追求原始性能通常倾向于使用ReiserFS,而重视数据完整性则首 选ext3.

(总结)CentOS Linux下配置Oracle 11gR2为系统服务自动启动

- - 服务器运维与网站架构|Linux运维|互联网研究
PS:在Windows下安装完成Oracle 11gR2后,默认就开机自启动Oracle相关服务,但Linux下安装完后每次都得手动启动和关闭数据库(dbstart | dbshut)、监听器(lsnrctl)、控制台(emtcl). 如何把Oracle添加到Linux系统服务里开机自启动呢. 下面以CentOS 6.3为例详解,其他发行版一样通用.

[总结] 6家移动互联网广告公司系统功能对比

- - 牛国柱
截止到今天,用6周的时间对6家移动广告公司的系统进行了分析和研究,1家是国外的AdMob,5家是国内的力美、多盟、有米、微云和安沃,这5家广告公司应该是国内比较领先的移动广告公司. 对这6家公司广告系统的研究,应该能大概了解国内外移动广告市场技术、业务发展的的大致状况. 至此,对移动广告系统的研究告一段落,不再分析其他公司的系统.