分布式事务处理方案,微服事务处理方案

微服事务处理方案(分布式事务处理方案)

1. 什么是事务

由一组操作构成的可靠、 独立的工作单元。 事务具有以下特点:

•Atomicity(原子性)

•Consistency(一致性)

•Isolation(隔离性)

•Durability(持久性)

2.事务的一致性

单体应用可以在数据库的事物管理器中获得强一致性,这种本地事物可靠简单。 而在微服或者SOA的场景下,我们的本地事物就不作用了。对于分布式系统 Google 提出 CAP定理 , 分布式的事物只能同时拥有以下三项中的两个:

•Consistency(一致性): 所有 用户看到一致的数据。

•Availability(可用性): 总能找 到一个可用的数据复本。

•Tolerance to Network Partition(分区容忍性): 即使 在系统被分区的情况下,仍然满足上述两点。

分布式系统的事物无法做到强一致性,只能做到最终一致性。

3.常见分布式事物的处理方案

  • 2pc 两段提交方案
  • 3pc 三段提交方案,是两段提交方案的进化。
  • TCC 模式 try ,confirm ,cancel。
  • 可靠消息机制 ,可靠消息分为 非事物消息 和 事物消息。

事物消息,简单的说就是消息投递成功,你本地的数据库事物肯定提交成功,消息投递失败你本地事物也肯定提交失败。相当于你投递消息和操作数据库是绑定在一起的,两者是在同一个事物中。

非事物消息,简单的说就是消息投递成功,本地数据库事物不一定执行成功。

而现有的开源的MQ框架 大多数是不支持 事物消息的,也没有和本地事物进行配合。 RocketMQ 好像实现了这个事物消息功能,有兴趣的同学可以去看看。

可靠消息机制保证数据一致性的解决方案(非事物消息)

先来看个案例: 假设我有一个 文章微服 负责发布文章,查询文章列表等,还有一个 用户微服 保持用户的一些基本信息,如:用户发文章的篇数等。

现在发文章在 文章微服,而用户的发文篇数在 用户微服。这种情况下我们怎么保证 发文的计数 不会多也不会少,保证其的一致性的呢?

大家先来看一段代码: 假设这是 文章微服 发文代码:

@Transactional
    public void saveArticle(Article article){
        try{
            //保存文章
            articleDao.saveArticle(article);
            MqEvent saveArticleEvent = new MqEvent();
            //消息ID 
            saveArticleEvent.setMsgId(UUIDUtil.mongoObjectId());
            //发送保存文章 事件个用户服务
            sender.sendAddArticleMqEvent(saveArticleEvent);
        }catch (Exception e){
            //抛异常 让事务回滚
            throw new RuntimeException();
        }
    }
}
复制代码

看起来很正常呀!没有什么问题! 我们来列举一下可能会出现的情况;

  1. 保存文章正常,MQ发送也正常,好万事大吉,数据都正常。

  2. 保存文章正常,MQ发送失败,抛异常。这时数据回滚,虽然出了点问题 但是数据正常。这也没问题。

  3. 文章保存失败,这时肯定抛异常,MQ发送走不到,这时也是正常的。

  4. 文章保存成功,MQ发送成功,这时会不会有问题出现呢? 刚刚我们说了 我们的MQ是非事物性的,恰巧这个时候 MQ 回执异常导致 MQ抛异常了。本地事物回滚,但是MQ虽然抛异常,消息却发成功了。这时候 会导致 用户发文计数多了一篇,数据不一致了导致。

虽然这种做法看起来没有什么问题,但其实是有问题的。

为了解决这个问题,我们需要 增加一个本地事件表,专门存放 MQ事件 ,有定时器轮训去发送MQ消息,发送成功后做标记,或者删除。很多MQ都会有 消息回执的。当成功投递到消息队列是 就会得到回执。

于是我们的代码应该改成这样:

  @Transactional
    public void saveArticle(Article article) {
        articleDao.saveArticle(article);
        MqEvent saveArticleEvent = new MqEvent();
        //消息ID
        saveArticleEvent.setMsgId(UUIDUtil.mongoObjectId());
        // 保存事件到事件表
        mqEventDao.addMQEvent(saveArticleEvent);
    }
复制代码

这样在本地事物的强一致性下可以保证,发文的同事插入发文事件。

说说 用户微服那边的处理 , 用户微服也应该有一个这样的事件表,保存接收的事件,通过轮训等方式处理这些事件,只有成功的接收了事件,事件才能从MQ队列里面消失。MQ在消费消息的时候如果遇到异常会重新将消失重新发回到队列中,很多MQ具有这个特性。

细心的同学可能会想到我同一个事件消息投递了两次怎么办?这就涉及幂等性的设计了,看到上面的消息ID没? 这就是为幂等性设计的 唯一ID;当用户微服收到两个消息ID是一样的时候,丢弃掉一个。

总结

我们的微服系统 只要涉及 增 删 改 的操作都应该通过可靠事件进行操作,而不能直接通过 REST 接口,去操作,也不能直接的发送事件去操作。对于消防端,要做好幂等性的处理。可靠事件处理微服的事物算是比较靠谱的做法,2pc,3pc ,Tcc 在微服事物处理这一块,基本上起不了什么作用。 本人的理解大概是这样,欢迎大家提出疑问。

转载于:https://juejin.im/post/5ccd4794f265da03a436e06b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式事务处理是指在分布式系统中,多个节点之间需要协同完成一个事务操作,并保证事务的一致性和可靠性。在分布式系统中,由于网络延迟、节点故障等原因,事务处理变得复杂。为了解决这个问题,可以采用以下几种常见的分布式事务处理方式: 1. 两阶段提交(Two-Phase Commit,2PC):2PC是一种经典的分布式事务协议,它通过协调者和参与者的交互来保证事务的一致性。在2PC中,协调者先向所有参与者发送准备请求,并等待参与者的响应。然后,协调者根据参与者的响应决定是否提交或中止事务。 2. 补偿事务(Compensating Transaction):补偿事务是一种基于回滚操作的分布式事务处理方式。当某个节点出现故障或事务失败时,可以通过执行相应的补偿操作来回滚已经执行的操作,以保证事务的一致性。 3. 基于消息队列的事务(Transactional Messaging):在分布式系统中,可以使用消息队列来实现异步通信和事务处理。参与者将事务操作封装成消息发送到消息队列中,然后协调者监听消息队列,根据消息的状态来决定是否提交或中止事务。 4. 分布式数据库事务处理:一些分布式数据库系统提供了内置的分布式事务处理功能,例如MySQL Cluster、TiDB等。这些数据库系统通过分片、复制、一致性协议等技术来实现分布式事务处理。 需要根据具体的场景和需求选择合适的分布式事务处理方式,以保证系统的一致性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值