我说分布式事务之最大努力通知型事务

复制代码

TCC适用于公司内部对一致性、实时性要求较高的业务场景,而本文咱们讲解的“最大努力通知型事务”是为解决跨网络、跨服务之间的柔性事务的另外一种解决方案。数据库

首先看一下最大努力通知型的流程图,以下图bash

我说分布式事务之最大努力通知型事务


咱们根据图中的内容,逐步分析一下该方案的业务流程。网络

1. 原理并发

首先阐述一下该方案的原理,根据图中所示,框架

业务活动的主动方(通知发起方),在完成本地业务活动处理后,会向业务活动被动方发送消息【箭头1】, 将业务执行结果通知给业务被动方【箭头4】。这个过程容许消息丢失,若是发生丢失的状况,服务主动方可以经过重试尽力实现双方的数据一致性。此处的的重试就体现出了–最大努力 的特色。异步

而后是业务的被动方。业务被动方会暴露一个业务结果接收接口(或者叫回调接口也能够)给业务主动方【箭头4】,对收到的通知消息进行必要的校验,校验经过后执行本地业务,从而使业务达到闭环。分布式

同时,因为主动方对被动方的通知次数是有限的,即咱们不可能无限制的通知,所以业务活动主动方须要提供一个业务查询补偿接口供被动方使用【箭头5】,被动方会根据定时策略,向业务活动的主动方发起查询操做,从而对丢失的业务消息达到补偿的目的。优化

整个过程当中,业务被动方暴露给主动方的通知接收接口 以及 业务主动方提供给被动方进行查询操做的接口均须要实现幂等,这样才能保证数据完整性不会被破坏,从而实现最终一致性。spa

2. 详解code

接下来,咱们详细展开对该方案的讲解。

在这个方案中,咱们要求被动方的业务处理结果不能影响业务主动方的处理,双方的职责是清晰的,例如:咱们接入支付宝的支付功能,我方的身份即业务被动方,而支付宝方则为业务主动方。

我方接收到用户的支付请求,等待用户输入支付密码,用户支付确认后,我方向支付宝发起支付请求,同步返回给用户预支付结果。此时,用户看到支付处理中。

当支付宝侧执行转帐完成以后(图中的箭头1),结果能够是成功/失败,总之主动方必定是在本地业务有肯定的执行结果后,才会发起通知。

支付宝侧会经过某种机制(猜测是图中的消息队列机制)将通知请求扔到通知消息服务中,通知发送核心业务消费通知消息,并记录持久化消息到数据库中,发送通知消息给我方。

我方支付回调接口收到支付完成通知后,会对参数进行签名校验,待签名经过后,取出业务参数,对这笔支付订单返回的结果进行后续操做(修改状态为下单完成并发货或者修改成支付失败,操做回滚/退款)。

这个过程理想状态下是很快的,因为支付宝侧强大的处理能力,咱们几乎感受不处处理中状态,但整个过程确实是异步的过程。

【这里给咱们的启示之一即是,对于跨系统的交互,若是可以将同步的业务操做拆分为异步过程,可以大幅度提升业务的灵活度及吞吐量。】


这里存在一种广泛的状况,咱们的系统处理能力是有限的,在收到通知后未能及时的处理完成,这时,双方会约定,若是收到通知且处理完成,业务被动方须要返回肯定某个状态码,如:“success”,不然认为这次通知失败。

这样,只要咱们处理完成就返回“success”,主动方就不会继续通知。不然,主动方会按照必定策略,好比“时间衰减策略”,对通知失败的请求从持久层中取出,好比:24小时内,按照间隔1min、5min、10min、30min、1h、2h、5h、10h的方式,逐步拉大通知间隔,直到达到通知要求的时间窗口上限。这时,就须要被动法主动发起查询。通常这种状况不多,而这么作的目的也是为了使最近的请求更快的被通知回去,咱们认为,时间越靠后,通知成功的可能性越少,由于大多数的通知请求在第一次通知发起时就返回了成功success。

PS:这里还有一种措施,就是人工干预,重置通知位点。好比:若是达到最大通知次数依然没有通知成功,那么数据仍旧保存在通知库里面,运营人员在接收到商户的重复通知需求的时候,经过人工的操做,从新重置通知次数,这样消息就能够从新通知了。

这种状况每每是业务被动方未接入主动查询致使的,不建议频繁采用此方案,正常的流程时在开发阶段就强烈要求被动方将通知接口及查询接口均开发完成。

说多了都是泪,笔者曾经在工做中从事过一段时间商户接入工做,就遇到过这种类型的商户,常常要求咱们为他们从新发起通知,对工做效率的影响真是肉眼可见的。


咱们说回正题,在异常状况下,若是业务主动方在必定时间阈值内未能及时的发起通知,而做为业务被动方的咱们又想及时获取到业务结果,这时就须要业务被动方主动发起查询,调用主动方暴露的查询接口获取业务结果,这里通常采用定时做业轮询,从而在业务上达到闭环, 最大可能的保证了数据的一致性。

3. 方案评价

  1. 方案成本:该方案成本较低,主要花费在业务查询与校对系统建设成本。校对系统是单独的,例如离线的文件对帐方式,经过双方定时导出日订单,作线下的互相对帐,从而实现平帐操做。
  2. 适用范围:本方案适用于对时间敏感性较低的业务,好比充值、转帐业务,在内部系统间就不适合该方式。多适用于跨系统、跨业务、跨网络的服务间数据一致性保证场景。
  3. 用到的服务模式为: 可查询操做,幂等操做等。
  4. 方案特色:
  5. 业务活动的主动方在完成业务处理后,向被动方发送通知消息(容许消息丢失);
  6. 主动方能够设置时间阶梯型通知规则,在通知失败后按规则重复发起通知,直到通知N次后再也不通知
  7. 主动方提供校对查询接口给被动方,被动方按需校对查询,用于恢复丢失的业务消息
  8. 应用案例
  9. 支付渠道接入通知,银行转帐通知、商户通知等
  10. 对帐通知(实时/定时)


4. 实现方式

从本文开始的图中能够看出,一般采用两种方式实现

  • 定时任务,使用定时做业轮询发起直接通知,通知数据要作持久化操做。几乎无外部依赖。
  • 定时消息队列,基于定时消息发起通知,一样须要对通知请求数据作持久化操做,对消息队列有高可用需求。


5. 如何优化


  1. 在业务系统外增长业务管理系统,对通知失败数据进行管理,实现手动触发重复通知操做。
  2. 将通知服务通用化,框架化,剥离通知逻辑与业务逻辑, 对通知队列进行区分, 不一样队列使用不一样通知规则,而且支持通知策略的可配置性操做等。
  3. 保证通知服务的可用性,必要时创建独立的数据库,这里要注意对通知数据的持久化策略,以及通知失败后从新发起通知的策略的优化,好比时间衰减策略的设置等。这对通知的成功率和实效性有很大影响。
  4. 要求主动方提供的业务查询接口及被动方暴露的通知处理业务接口均要实现幂等性。
  5. 最后要注意,内存调优与流量控制,这里主要针对业务主动方,若是通知消息的生产方的速率与通知发送侧的消费方的消费速率不匹配,会致使大量消息驻留在消费端内存中,致使消息服务响应慢,甚至挂掉,从而影响到服务被动方进行业务后续处理,致使更大的商业纠纷等。(这里再插一句,考虑到极端状况,若是真的出现down机,在服务重启后,要能恢复现场,所以对通知消息的持久化操做就是必不可少的。当服务重启后,通知服务可以定位到上次的消费位点,继续通知操做)
我说分布式事务之最大努力通知型事务

6. 小结


本文对分布式事务解决方案的– 最大努力通知型 柔性解决方案进行了较为详细的讲解,结合实例及笔者的工做经历,对方案的各个细节展开讲解,但愿可以对读者有所帮助。

后续笔者会着手开发一款分布式事务的轮子,入手点将采用本文提到的模式,并最终达到基本可用。算是立了一个flag吧,完成以后会第一时间发文出来。(又一个有生之年系列)

到目前为止,《我说分布式事务》 系列就过半了,以后我会对可靠消息一致性方案进行讲解,咱们不见不散。

相关文章
相关标签/搜索