美文网首页
分布式事务-消息驱动模型

分布式事务-消息驱动模型

作者: AlexanderLuo | 来源:发表于2019-08-11 21:23 被阅读0次

一句话:

分布式事务发起方和联动方割裂开来,通过记录跟分析前一个事务的运行状态,决定下一步的行为是回
滚还是开启下游事务

具体点

"割裂":
    割裂意味着每个事务是独立提交的,这是最终一致模型。从代码上来开,也不再是同一个方法内,
    通过调用开启另外的事务了。即原来的业务逻辑:
        func(){
            执行本地事务A
            执行远程事务B
        }
        
    割裂后业务逻辑:
        func(){
            执行本地事务A
            在事务A提交的同时记录事务信息
        }
        

"记录跟分析前一个事务的运行状态":
    先谈谈如何记录事务的运行状态信息。我们最容易想到的方案就是在同一个本地事务内,提交的同
    时插入一条事务状态信息数据即可。这样,只要我们保证了事务提交,必然有相关信息数据持久,
    对一个分布式事务而言,我们可用唯一的xid字段去标记,如此,无论这一组次的子事务状态数据
    是否在同一个库,我们都能轻易的找到他们。

    另外,在事务提交的同时,如果能够发送一条可靠消息,那么也能达到持久的目的,这是消息驱动
    采用的方式,但在后面会说到,发送一条可靠消息,可能并不是那么容易。


"去决定下一步的行为":
    我们不妨从分布式事务的源头来看,发起方的本地事务提交了,假如相关的带有唯一标志xid的事
    务信息被插入了数据库,这个时候,如果我们有一个独立的观察者,发现了这样的一条事务信息,
    若检查事务信息的状态是本地提交,那么观察者会根据相关的业务信息去开启下游事务逻辑,直至
    整个业务逻辑完成,或执行各自的回滚逻辑,这便是消息驱动的核心原理。
    
    思考一下,独立的观察者的实现方案。
   
    1。可以通过异步的定时任务去捞取信息
    2。可以通过订阅binlog去实现事务信息的消费
    3。借助于消息中间件MQ,这是本章将介绍的内容
    
    我们采用MQ的模式,于是整个分布式事务的逻辑变成了这样:        
    
        提交上游事务 -> 发送了一条可靠消息  -> 下游事务消费消息  -> 回滚或者继续驱动 

更进一步

消息驱动的链路逻辑清楚了,但是这条链路上的问题依旧很多,这里我们进入更深一步的讨论。

1。如何在上游事务提交的同时发送一条可靠消息。
    
    从单个事务的生命周期来看,我们无外乎在提交前跟提交后发送消息而已,假设先在MQ正常的情况
    下讨论
    
    a.如果在提交前发送消息,本地事务异常失败了,消息却被消费了,明显产生了问题。
    b.如果在提交后发送消息,jvm挂了或者网络问题,引发消息发送失败,这又产生了问题。
    
    其实解决也不复杂,我们只需要在提交前发送一种不被消费的消息,在提交后再修改这条消息的状
    态让它具备被消费的能力即可,这种功能在RocketMq被叫做事务消息,没有被确认状态的消息称为
    半消息。
    
    回头看
    问题a 被解决了,没有被确认的消息叫做半消息,不能被消费,我们借助于发送消息的ack机制,
    保证事务提交前发送成功。
    
    在看问题b 半消息发送了,本地事务提交后jvm挂掉了,怎么办? 聪明的你已经想到了,那就是和
    本地事务一同插入的,本地事务表信息!
    
    我们提供给mq一个回查机制,当半消息迟迟得不到确认,那么去回查,发现相关xid标记的本地事
    务已经插入了且状态是本地已经提交了,那么自然而然,这条半消息状态可以修改为已完成,可以
    被消费了。
    
    否则呢?否则这条消息就应该状态修改为回滚!让相关的消费服务执行回滚逻辑!
    
2。如何保证能够正确的消费掉这条事物消息
    消费方需要做到接口等幂,若多次尝试消费失败,最终到达死信队列。

简单总结

对比TCC方案,很明显,我们不要去做最难的业务资源预留的设计。
借助于中间件,提升了维护难度,还是买人家的服务来用吧。

相关文章

网友评论

      本文标题:分布式事务-消息驱动模型

      本文链接:https://www.haomeiwen.com/subject/zzfejctx.html