包含事件通知分布式数据一致性的词条

来源网友投稿 771 2023-01-31

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。
本篇文章给大家谈谈事件通知分布式数据一致性,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 今天给各位分享事件通知分布式数据一致性的知识,其中也会对进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

保证分布式系统数据一致性的6种方案

编者按 :本文由「高可用架构后花园」群讨论整理而成。

有人的地方,就有江湖

有江湖的地方,就有纷争

在电商等业务中,系统一般由多个独立的服务组成,如何解决分布式调用时候数据的一致性?

具体业务场景如下,比如一个业务操作,如果同时调用服务 A、B、C,需要满足要么同时成功;要么同时失败。A、B、C 可能是多个不同部门开发、部署在不同服务器上的远程服务。

在分布式系统来说,如果不想牺牲一致性,CAP 理论告诉我们只能放弃可用性,这显然不能接受。为了便于讨论问题,先简单介绍下数据一致性的基础理论。

强一致

弱一致性

最终一致性

在工程实践上,为了保障系统的可用性,互联网系统大多将强一致性需求转换成最终一致性的需求,并通过系统执行幂等性的保证,保证数据的最终一致性。但在电商等场景中,对于数据一致性的解决方法和常见的互联网系统(如 MySQL 主从同步)又有一定区别,群友的讨论分成以下 6 种解决方案。

业务整合方案主要采用将接口整合到本地执行的方法。拿问题场景来说,则可以将服务 A、B、C 整合为一个服务 D 给业务,这个服务 D 再通过转换为本地事务的方式,比如服务 D 包含本地服务和服务 E,而服务 E 是本地服务 A ~ C 的整合。

优点: 解决(规避)了分布式事务。

缺点: 显而易见,把本来规划拆分好的业务,又耦合到了一起,业务职责不清晰,不利于维护。

由于这个方法存在明显缺点,通常不建议使用。

此方案的核心是将需要分布式处理的任务通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或消息队列,再通过业务规则自动或人工发起重试。人工重试更多的是应用于支付场景,通过对账系统对事后问题的处理。

消息日志方案的核心是保证服务接口的幂等性。

考虑到网络通讯失败、数据丢包等原因,如果接口不能保证幂等性,数据的唯一性将很难保证。

eBay 方式的主要思路如下。

Base:一种 Acid 的替代方案

此方案是 eBay 的架构师 Dan Pritchett 在 2008 年发表给 ACM 的文章,是一篇解释 BASE 原则,或者说最终一致性的经典文章。文中讨论了 BASE 与 ACID 原则在保证数据一致性的基本差异。

如果 ACID 为分区的数据库提供一致性的选择,那么如何实现可用性呢?答案是

BASE (basically available, soft state, eventually consistent)

BASE 的可用性是通过 支持局部故障 而不是系统全局故障来实现的。下面是一个简单的例子:如果将用户分区在 5 个数据库服务器上,BASE 设计鼓励类似的处理方式,一个用户数据库的故障只影响这台特定主机那 20% 的用户。这里不涉及任何魔法,不过它确实可以带来更高的可感知的系统可用性。

文章中描述了一个最常见的场景,如果产生了一笔交易,需要在交易表增加记录,同时还要修改用户表的金额。这两个表属于不同的远程服务,所以就涉及到分布式事务一致性的问题。

文中提出了一个经典的解决方法,将主要修改操作以及更新用户表的消息 放在一个本地事务 来完成。同时为了避免重复消费用户表消息带来的问题,达到多次重试的幂等性, 增加一个更新记录表 updates_applied 来记录已经处理过的消息。

系统的执行伪代码如下

(点击可全屏缩放图片)

基于以上方法,在第一阶段,通过本地的数据库的事务保障,增加了 transaction 表及消息队列 。

在第二阶段,分别读出消息队列(但不删除),通过判断更新记录表 updates_applied 来检测相关记录是否被执行,未被执行的记录会修改 user 表,然后增加一条操作记录到 updates_applied,事务执行成功之后再删除队列。

通过以上方法,达到了分布式系统的最终一致性。进一步了解 eBay 的方案可以参考文末链接。

随着业务规模不断地扩大,电商网站一般都要面临拆分之路。就是将原来一个单体应用拆分成多个不同职责的子系统。比如以前可能将面向用户、客户和运营的功能都放在一个系统里,现在拆分为订单中心、代理商管理、运营系统、报价中心、库存管理等多个子系统。

拆分首先要面临的是什么呢?

最开始的单体应用所有功能都在一起,存储也在一起。比如运营要取消某个订单,那直接去更新订单表状态,然后更新库存表就 ok 了。因为是单体应用,库在一起,这些都可以在一个事务里,由关系数据库来保证一致性。

但拆分之后就不同了,不同的子系统都有自己的存储。比如订单中心就只管理自己的订单库,而库存管理也有自己的库。那么运营系统取消订单的时候就是通过接口调用等方式来调用订单中心和库存管理的服务了,而不是直接去操作库。这就涉及一个『 分布式事务 』的问题。

分布式事务有两种解决方式

1. 优先使用异步消息。

上文已经说过,使用异步消息 Consumer 端需要实现幂等。

幂等有两种方式, 一种方式是业务逻辑保证幂等 。比如接到支付成功的消息订单状态变成支付完成,如果当前状态是支付完成,则再收到一个支付成功的消息则说明消息重复了,直接作为消息成功处理。

另外一种方式如果业务逻辑无法保证幂等,则要增加一个去重表或者类似的实现 。对于 producer 端在业务数据库的同实例上放一个消息库,发消息和业务操作在同一个本地事务里。发消息的时候消息并不立即发出,而是向消息库插入一条消息记录,然后在事务提交的时候再异步将消息发出,发送消息如果成功则将消息库里的消息删除,如果遇到消息队列服务异常或网络问题,消息没有成功发出那么消息就留在这里了,会有另外一个服务不断地将这些消息扫出重新发送。

2. 有的业务不适合异步消息的方式,事务的各个参与方都需要同步的得到结果。 这种情况的实现方式其实和上面类似,每个参与方的本地业务库的同实例上面放一个事务记录库。

比如 A 同步调用 B,C。A 本地事务成功的时候更新本地事务记录状态,B 和 C 同样。如果有一次 A 调用 B 失败了,这个失败可能是 B 真的失败了,也可能是调用超时,实际 B 成功。则由一个中心服务对比三方的事务记录表,做一个最终决定。假设现在三方的事务记录是 A 成功,B 失败,C 成功。那么最终决定有两种方式,根据具体场景:

对 b 场景做一个特殊说明:比如 B 是扣库存服务,在第一次调用的时候因为某种原因失败了,但是重试的时候库存已经变为 0,无法重试成功,这个时候只有回滚 A 和 C 了。

那么可能有人觉得在业务库的同实例里放消息库或事务记录库,会对业务侵入,业务还要关心这个库,是否一个合理的设计?

实际上可以依靠运维的手段来简化开发的侵入,我们的方法是让 DBA 在公司所有 MySQL 实例上预初始化这个库,通过框架层(消息的客户端或事务 RPC 框架)透明的在背后操作这个库,业务开发人员只需要关心自己的业务逻辑,不需要直接访问这个库。

总结起来,其实两种方式的根本原理是类似的,也就是 将分布式事务转换为多个本地事务,然后依靠重试等方式达到最终一致性 。

交易创建的一般性流程

我们把交易创建流程抽象出一系列可扩展的功能点,每个功能点都可以有多个实现(具体的实现之间有组合/互斥关系)。把各个功能点按照一定流程串起来,就完成了交易创建的过程。

面临的问题

每个功能点的实现都可能会依赖外部服务。那么如何保证各个服务之间的数据是一致的呢?比如锁定优惠券服务调用超时了,不能确定到底有没有锁券成功,该如何处理?再比如锁券成功了,但是扣减库存失败了,该如何处理?

方案选型

服务依赖过多,会带来管理复杂性增加和稳定性风险增大的问题。试想如果我们强依赖 10 个服务,9 个都执行成功了,最后一个执行失败了,那么是不是前面 9 个都要回滚掉?这个成本还是非常高的。

所以在拆分大的流程为多个小的本地事务的前提下,对于非实时、非强一致性的关联业务写入,在本地事务执行成功后,我们选择发消息通知、关联事务异步化执行的方案。

消息通知往往不能保证 100% 成功;且消息通知后,接收方业务是否能执行成功还是未知数。前者问题可以通过重试解决;后者可以选用事务消息来保证。

所以目前只剩下需要实时同步做、有强一致性要求的业务场景了。在交易创建过程中,锁券和扣减库存是这样的两个典型场景。

要保证多个系统间数据一致,乍一看,必须要引入分布式事务框架才能解决。但引入非常重的类似二阶段提交分布式事务框架会带来复杂性的急剧上升;在电商领域,绝对的强一致是过于理想化的,我们可以选择准实时的最终一致性。

我们在交易创建流程中, 首先创建一个不可见订单 ,然后在同步调用锁券和扣减库存时,针对调用异常(失败或者超时),发出废单消息到MQ。如果消息发送失败,本地会做时间阶梯式的异步重试;优惠券系统和库存系统收到消息后,会进行判断是否需要做业务回滚,这样就准实时地保证了多个本地事务的最终一致性。

业界常用的还有支付宝的一种 xts 方案,由支付宝在 2PC 的基础上改进而来。主要思路如下,大部分信息引用自官方网站。

分布式事务服务简介

分布式事务服务 (Distributed Transaction Service, DTS) 是一个分布式事务框架,用来保障在大规模分布式环境下事务的最终一致性。DTS 从架构上分为 xts-client 和 xts-server 两部分,前者是一个嵌入客户端应用的 JAR 包,主要负责事务数据的写入和处理;后者是一个独立的系统,主要负责异常事务的恢复。

核心特性

传统关系型数据库的事务模型必须遵守 ACID 原则。在单数据库模式下,ACID 模型能有效保障数据的完整性,但是在大规模分布式环境下,一个业务往往会跨越多个数据库,如何保证这多个数据库之间的数据一致性,需要其他行之有效的策略。在 JavaEE 规范中使用 2PC (2 Phase Commit, 两阶段提交) 来处理跨 DB 环境下的事务问题,但是 2PC 是反可伸缩模式,也就是说,在事务处理过程中,参与者需要一直持有资源直到整个分布式事务结束。这样,当业务规模达到千万级以上时,2PC 的局限性就越来越明显,系统可伸缩性会变得很差。基于此,我们采用 BASE 的思想实现了一套类似 2PC 的分布式事务方案,这就是 DTS。DTS在充分保障分布式环境下高可用性、高可靠性的同时兼顾数据一致性的要求,其最大的特点是保证数据最终一致 (Eventually consistent)。

简单的说,DTS 框架有如下特性:

以下是分布式事务框架的流程图

实现

与 2PC 协议比较

1. 电商业务

公司的支付部门,通过接入其它第三方支付系统来提供支付服务给业务部门,支付服务是一个基于 Dubbo 的 RPC 服务。

对于业务部门来说,电商部门的订单支付,需要调用

从业务规则上需要同时保证业务数据的实时性和一致性,也就是支付成功必须加积分。

我们采用的方式是同步调用,首先处理本地事务业务。考虑到积分业务比较单一且业务影响低于支付,由积分平台提供增加与回撤接口。

具体的流程是先调用积分平台增加用户积分,再调用支付平台进行支付处理,如果处理失败,catch 方法调用积分平台的回撤方法,将本次处理的积分订单回撤。

(点击图片可以全屏缩放)

2. 用户信息变更

分布式服务对衍生的配套系统要求比较多,特别是我们基于消息、日志的最终一致性方案,需要考虑消息的积压、消费情况、监控、报警等。

In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability.

英文版 : http://queue.acm.org/detail.cfm?id=1394128

中文版: http://article.yeeyan.org/view/167444/125572

感谢李玉福、余昭辉、蘑菇街七公提供方案,其他多位群成员对本文内容亦有贡献。

本文编辑李玉福、Tim Yang,转载请注明来自@高可用架构

如何解决分布式系统数据事务一致性问题

文探讨了在分布式系统中,如何基于业务方面的考量、将RESTful与MQ(消息中间件)结合、解决事务完整性/数据一致性问题的架构设计。
一、面向业务考量的最终一致性方案考虑
这里先举两个例子。
1、支付宝的“WS Transaction标准”尝试:
支付宝在他们的分布式系统中为解决事务完整性的问题,曾经尝试过WS Transaction标准,但是经过实际做测试,最后发现成本实在是太高了。完成一个事务,为确保事务完整性,20多条的消息的交互,其中只有1条是业务消息,其他都是系统之间的协议消息。这就会导致客户端响应太慢,客户无法承受这样的性能。
2、Ebay架构师的最终一致性方案:
来自Ebay的架构师根据他们的最佳实践给出过解决方案。就是关于数据一致性的,比如他们的分布式存储如何保持数据一致性。其中探讨了“实时一致”与“严格事务”之间的悖论,他们采用了局部实时一致、全局最终一致的解决方案。在这里就需要从业务上辨别哪些操作是可以放宽的(允许不在一个事务中),哪些操作必须是原子性的。现在Ebay的整个架构就是基于“最终一致性”的,支付宝也从中受到启发,沿用该设计思路解决了“客户端迅速响应”和“服务端数据一致”的矛盾。
故考虑系统架构设计的时候,不仅仅考虑技术,也把业务因素考虑进来,面向业务考量进行系统设计,会让我们在技术上做出更合理的抉择。基于业务考虑,有利于得出事务的优先级别,也有利于作出架构设计上的最佳取舍。通常来说银行、证券系统的事务完整性(或者说数据一致性)具有绝对优先级,也就要求绝对严格的实时保证。而通讯系统在事务完整性(或者说数据一致性上)的优先级别上甚至没有支付宝和Ebay高,这两者都有复杂的帐务交易。如果他们也认为局部实时一致、全局最终一致就能够满足业务的要求,那么自然在通讯系统中也有其可行性。
二、Restful与MQ技术适用场景分析
一般而言Restful技术架构为对客户端开放的一组资源服务。在分布式系统中既有客户端与服务器之间的交互,又有服务器与服务器之间的交互。比如说XCAP协议就是标准的Restful风格的接口,提供客户端远程操作XML文档的服务,而“运营管理系统”调用其他业务系统接口,用以管理用户可被分配的服务以及权限等,则是服务器之间的信息交互。前者当然适合Restful风格的技术接口,后者个人更倾向于异步的、基于消息的通信方式。因为客户端与服务器通常是跨越互联网的,而服务器与服务器之间可能位于一个局域网内,甚至可能被安放在同一个机房。
我们知道Restful风格的技术架构通常是通过JSON或者XML等进行信息的传递,总之都是通过“字符串格式”的封装进行信息传递。通过字符格式交互信息在使用上带来简便的同时,因为封装、解析、转换等过程使其在性能自然要付出一些代价,如果是服务器之间在更底层同类协议之间的数据交互性能就要高的多。这里顺便提到信息交互在不同场景下的性能顺序,按照从快到慢排序:
1、同一进程之间的信息交互;
2、同一机器两个进程之间的信息交互;
3、两个分布机器之间的信息交互。
因为HTTP是在TCP/IP协议之上的包装,WebService是在HTTP协议之上的包装,根据越低层协议之间的信息交互越高效的特征,从协议级由快到慢排序:
1、基于TCP/IP协议的信息交互;
2、基于HTTP协议的信息交互;
3、基于WebService协议的信息交互。
另外,因为“运营管理系统”与其他系统之间是直接交互的,比如运营要给某个用户开通某些特定服务,那就要分别调用提供这几个服务的业务系统的“细粒度”接口。一旦增加新的服务,也势必影响到运营管理系统的修改。我们说在分布式系统中有个原则,尽可能设计“粗粒度”接口,以减少系统之间的网络交互。如果在运营管理系统与其他业务系统之间由“消息中间件”来进行信息交互,那么:
1、运营管理系统可以设计面向服务的“粗粒度”接口,开通几个服务只需要把几种类型的数据封装在一起,一次性传递给MQ。增加服务也只不过增加一种数据类型而已;
2、MQ可以保证消息最终一定会被接收、处理。因为MQ可以实现基于“订阅-通知”的Event-Driven机制,业务系统只要在MQ中注册自己,就可以实时收到来自MQ的消息。即使出现系统或者网络异常,消息也会被MQ中间件持久化,一旦业务系统恢复,消息马上会被发往业务系统,这显然比目前采用的每隔一段时间扫描一次数据库要高效的多。
三、MQ与最终一致性
MQ消息队列技术是分布式应用间交换信息的一种技术。消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读走。通过消息队列,应用程序可独立地执行——它们不需要知道彼此的位置、或在继续执行前不需要等待接收程序接收此消息。它为构造异步方式实现的分布式应用提供了松耦合方法,在应用中以执行多种功能,比如要求服务、交换信息或异步处理等。
在分布式系统中,尤其是不同语言的分布式系统中,如果没有消息中间件完成信息交换,应用开发者为了高效传输数据,就要编写相应语言的应用程序来发送和接收信息,且交换信息没有标准方法,每个应用必须进行特定的编程从而和多平台、不同环境下的一个或多个应用通信。
假如系统可以采用数据“局部实时一致、全局最终一致”的方案,就可以选择不需要支持事务的MQ中间件,因为其可以保证:即使在系统异常、网络异常等特殊情况下,消息也会被持久化,当系统恢复,消息马上会被处理,也即最终一定会被接受处理,也就是最终一致。而不需要支持事务的MQ性能及吞吐率都会很高。
总之,个人倾向于用 Restful对客户端提供服务,服务器之间引入MQ服务,建立异步的、基于消息的信息交互方式,并基于数据局部实时一致、全局最终一致的原则,来解决事务问题。

数据一致性问题

最近在整理线上问题时发现绝大部分的问题都是由于数据不一致导致的,而且这类问题往往也比较难处理,那一般数据一致性都是由哪些原因造成的呢。

问题case最多的就是分布式场景下的数据一致性问题,这也是比较难规避的的场景。

分布式数据一致性通常分为两种,一种是对实时性要求较高的一致性(同步链路一致性); 一种是可以接受短暂不一致的场景(异步链路一致性)。

异步链路一致性问题一般有一部分主要数据与依赖数据组成,例如用户支付完成之后需要给用户发放红包,短信通知等。这种场景通常通过消息的方式来实现。消息实现最终一致性主要要考虑消息顺序、消息幂等以及事务性消息等问题。另外一种常用的方式是通过任务队列来进行重试。两种方式思路都是通过将次要系统的更新与主链路解耦开,然后通过重试的方式来达到一致性。

相比异步链路一致性问题,同步的处理起来会复杂一些。

比如经典的下单问题,下单过程中需要调用库存、优惠券等多个系统,过程中出现不一致如何处理。常见的处理方式通过两阶段提交加消息的方式来解决,即先生成不可见订单,然后依次调用库存、优惠券等系统,如果所有调用成功,将订单设置为可见;如果中间出现调用某个系统失败,这个时候会发送废单消息,各个系统通过监听废单消息做对应的反操作。可以看到同步链路是的第二阶段与异步链路的处理方式类似,只不过多了一步预先的操作。

另外一个问题与这个相反,当用户生成一笔付款单时,需要在支付平台生成一笔支付相关的单据,如果底层的支付单据成功而付款单没有成功,这个时候就会产生问题,用户可以通过线下转账成功,但是没有对应的付款单据,这个是不可接受的。也就是说付款单成功时支付单可以短暂的不成功,反过来却不行。但是系统的发起方又是从付款单开始。
单库场景出现数据不一致只能是数据的更新没有放到同一个事务中,目前我遇到的主要有两种情况。

例如在一个支付系统中,当支付完成时先更新了支付核心(paycore)的数据,在更新完支付核心之后再推进收单层数据的更新,当更新收单层时如果出现锁冲突等异常时,就会出现系统数据的不一致。

一个可选的方式是使用一个待更新的context,每个层次将要修改的数据先放到这个context中,然后最后在同一的公共模块中对所有的数据进行一次的更新操作。

另外一点值得注意的是系统的事务调用关系不要弄的太复杂,过多的事务嵌套会导致事务的边界不清,容易造成数据的不一致。如果所有的数据需要保证一致,最好只开一次事务完成所有的更新。
最开始系统设计的时候只有数据B需要更新,而系统中存在多处更新的入口。
随着业务的发展,这时数据添加的了B1,当更新B时需要同时更新B1,而往往这个时候只考虑了主要链路,而忽视了其它分支入口。因此当新增了关联数据更新时,需要去评估更新的入口来源,将更新封装起来,修改所有的更新入口。
当我们进行系统设计时,首先需要去梳理下哪些数据需要保证一致性,然后思考下会有哪些不一致的情况,分别属于什么case,然后使用对应的一些解决方案。

在分布式场景很难保证数据的一致性,即使使用了重试机制等还是会出现少量的不一致,如果这些不一致是无法接受的,那还需要使用一些核对的机制(实时核对、离线核对)来快速的发现问题,保证及时的进行人工的处理。
参考:

https://www.jianshu.com/p/1156151e20c8 关于事件通知分布式数据一致性和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。 事件通知分布式数据一致性的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、事件通知分布式数据一致性的信息别忘了在本站进行查找喔。
上一篇:普宁智能运维平台(普宁智能运维平台官网)
下一篇:智能化运维解决方案(智能运维模块)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~