分布式事务之最终一致性

问题描述

比如有订单,库存两个数据,一个下单过程简化为,加一个订单,减一个库存。 而订单和库存是独立的服务,那怎么保证数据一致性。

这时候我们需要思考一下,怎么保证两个远程调用“同时成功”,数据一致?

请大家先注意一点远程调用最郁闷的地方就是,结果有3种,成功、失败和超时。 超时的话,成功失败都有可能。而超时的结果是无法预测的,超时之后可能成功也可能失败,如果超时重试成功,但是本地事务已经回滚,而消息却消费成功了,这时候就不一致了。

一般的解决方案,大多数的做法是借助mq来做最终一致。(目前只有rocketmq支持事务消息,本文介绍背景采用的是rabbitmq)

 

为什么使用mq

那么针对最终一致性为什么要使用mq呢?我想很多人也知道网上很多人在说mq实现最终一致性,但是从来没有仔细想想为什么要用mq。我列出这几个原因来供你参考:
1、mq可以解决http请求出现异常的时候带来的一系列问题
2、mq可以有多个消费者,完全契合微服务
3、mq本质是队列,在高并发下,可以保证你的数据正常

 

 

实现流程

下面是一种可靠消息最终一致性事务方案的实现流程:

Eventually Consistency

正常流程:

  1. A 系统发送预发送消息给消息服务系统

  2. 消息服务系统存储预发送的消息到消息数据库。

  3. 消息服务系统返回存储预发送消息的结果到 A 系统

  4. 如果第 3 步返回的结果是成功的, A 系统则执行业务操作,否则不执行。

  5. A 系统业务操作成功后,通知消息服务系统 。

  6. 消息服务系统发送消息到 MQ ,并且更新预发送消息状态为已发送(同一个事务内)。

  7. MQ 发送消息到 B 系统

  8. B 系统执行业务操作,保证幂等性,防止同一个消息重复执行,如果是业务失败,则发送消息通知A回滚。

  9. B 系统向 MQ ack 此条消息,并向消息服务系统进行确认成功消费消息,让消息服务系统将消息状态置为已消费

  10. 消息恢复系统定时去消息服务系统查一下消息数据,查看有没有状态为已消费预发送已发送)状态的超时(比如 2 分钟以上还未消费的)消息。

  11. 如果第 10 步发现有非已消费状态的超时消息,调用 A 系统提供的查询接口,查询次条消息对应的业务数据是否为处理成功。

  12. 如果业务数据是处理成功的状态,那么就再次调用确认并发送消息,即进入第 6 步。如果业务数据是处理失败的,那么就调用消息服务系统进行删除该条消息数据。

再来看看有错(比如说网络断了或者服务器挂了)的时候,这个系统是怎么保证一致性的:

  • 第 1 步失败,相当于什么都没做。
  • 第 2 步失败,第 3 步会返回失败结果,A 系统不执行业务操作。
  • 第 3 步失败,A 系统不执行业务操作,消息恢复系统在第 12 步判断业务处理失败。
  • 第 4 步失败,A 系统回滚业务,同样消息恢复系统在第 12 步判断业务处理失败。
  • 第 5、6、7、8、9 步失败,消息恢复系统在第 12 步判断业务处理成功,重试第 6 步直到成功为止。如果在第 9 步失败了,B 系统会重复消费某条消息,所以 B 系统要设计成幂等操作,对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次调用而产生了副作用。

所以,只要消息数据持久化了,我就假设后面一定会被消费,就算后面挂了一堆东西,但是我们把挂掉的服务再全部启动,这条消息还是会被消费,不会丢失,可以保证最终一致性。

 

需要注意的问题

1、消息的100%投递
首先我们需要保证的就是消息一定要投递出去,要是我们消息都不能保证投递成功,那么后面的逻辑就走不下去了。

2、我们需要保证幂等性(无论多少次操作,最后造成的结果和只执行一次造成的结果是一样的。)
消息肯定会出现重复投递的问题,这里应该由消费端去保证,重复的消息不能进行消费。

 

 

参考:https://cloud.tencent.com/developer/article/1477485

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式系统中,可以使用以下方法来实现分布式事务最终一致性: 1. 事件驱动架构(Event-driven architecture):使用事件驱动的方式来实现最终一致性。当一个操作发生时,将相关的事件发布到消息队列或事件总线中,其他服务或组件通过订阅这些事件来获取并处理。通过异步处理和消息传递,系统可以在后台逐步更新和同步数据,最终达到一致状态。 2. 事务日志和重放(Transaction log and replay):将分布式事务的操作记录到事务日志中,并在需要时进行重放。当一个事务发生时,将事务操作记录到日志中,然后由一个或多个后台任务来按顺序读取日志并执行相应的操作。通过重放事务日志,系统可以在后台逐步更新和同步数据,最终达到一致状态。 3. 分布式副本(Distributed replicas):使用分布式副本来实现数据的最终一致性。将数据复制到多个副本节点,并使用一致性协议(如Paxos或Raft)来保证副本之间的一致性。当数据更新时,通过协议来确保所有副本最终达到一致状态。 4. 基于版本的控制(Version-based control):使用基于版本的控制机制来实现最终一致性。每个操作都会带有一个版本号,系统根据版本号进行冲突检测和解决,并将冲突的操作进行合并或处理。通过版本控制,系统可以在后台逐步解决冲突和同步数据,最终达到一致状态。 需要根据具体业务需求和系统架构来选择合适的方法来实现最终一致性,并在设计和实现时考虑可用性、性能、安全性等方面的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值