dubbo下的补偿实现(一)

背景

由于前面几篇文章涉及的问题 分布式事务的思考

在我们微服务的场景下 各种本地事务都没有办法控制的很好。

A服务调用B服务 当B服务成功提交之后 A发生了异常 这种情况下要如何处理呢???

思考

参考了上述文章后 我们不再一个劲的追求强一致性 而转而追求最终一致性

这也是从传统ACID转变为BASE 即所谓的酸碱中和【在英文中base有碱的意思】

ACID

A: Atomicity 原子性 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节
C: Consistency 一致性 事务开始之前和事务结束以后,数据库的完整性没有被破坏
I: Isolation 隔离性 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)
D: Durability 持久性 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

BASE

BA:Basically Available,基本可用性
S: Soft State 软状态 接受状态在一段时间内部同步
E:Eventually Consistent 最终一致性 在一定的时间窗口中,最终数据达成一致即可
软状态是实现 BASE 的方法,基本可用域最终一致性是必须到达的目标。以 BASE 的思想由于不保证强一致性,所有接受系统在一定时间内数据存在不一致,不过在处理请求的过程中,需要记录知道每次请求的状态,以后出现问题的时候,回滚到中间任何临时状态,达到最终一致性

分析

我们的思路是基于dubbo完成业务失败后的补偿 那么需要考虑如下几个问题

  1. 如何识别业务失败?
  2. 是否所有的rpc调用在失败后都需要补偿
  3. 补偿需要依据的数据从何处获得?
  4. 如何进行补偿?
  5. 补偿失败怎么处理?

思路

  1. 第一个问题比较简单 我们很容易想到和本地事务一起考虑 当本地事务出错发生回滚的时候任务业务失败 此时需要针对性的补偿
  2. 某些rpc接口只是单纯的进行获取数据 当然无需进行补偿 需要补偿的都是会对数据进行修改的 也就是说查询类等接口是无需补偿的
  3. 这个问题比较复杂 不过对于系统来说常见的方案就是依据【可补偿rpc方法===》姑且这么称呼吧】的参数或者返回值【比如返回了id等等】
  4. 由于分布式环境下的服务拆分 设想中补偿应该也发生在微服务被调用方 因此依然需要通过rpc进行调用【需要注意的是补偿方法不应该被业务调用】也就是说在发布服务方需要针对需要补偿的方法做一个特殊标记 同时针对该方法提供一个补偿方法 该补偿方法包含一些必要参数【比如可补偿方法的参数或者返回值等等】 当发生业务回滚需要被远程调用
  5. 可以针对性的重试【注意方法幂等,可以依靠状态机等等 不要额外抛出异常】当然重试也无法成功的话就通过日志 邮件 等人工提醒兜底