分布式事务

场景:分布式系统经常会出现机器宕机、网络异常、消息乱序、数据错误、不可靠的TCP、存储数据丢失,为了解决这些问题,需要使用分布式事务

一、知识点

CAP定理

  • C :一致性(Consistency)

在分布式系统中的所有数据备份,在同一时刻拥有相同的值

  • A :可用性(Availability)

在集群中一部分节点发生故障之后,集群整体是否还能被访问到(对于数据读写具有高可用性)

  • P :分区容错性(Partition tolerance)

大多数分布式系统都分布在多个子网络。每个子网络叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如一台服务器放在中国,另一台放在美国,如果他们中的线路断了,就可能无法通信。

CAP这三个要素最多只能同时实现两点,P是总是成立的的,因此只能CP、或者AP

分布式系统中实现一致性的raft算法:
http://thesecretlivesofdata.com/raft/

对于大多数互联网应用的场景,主机众多、部署分散,而且现在集群的规模越来越大,所以节点故障、网络故障是常态,而且要保证服务可用性达到99.9999%,即保障A和P,舍弃C

BASE 理论

BASE是指

  • 基本可用(Basically Available)

基本可用是指分布式系统出现故障的时候,允许损失部分可用性(例如响应时间、功能上的可用性),损失部分可用性不代表系统不可用
1、响应时间上的损失:正常情况下,搜索引擎只需要0.5s给用户返回查询结果,但由于出现故障,查询的结果响应时间慢了1-2秒
2、功能上的损失:购物网站在高峰期,为了保证系统稳定性,部分用户可能被引导到一个降级页面(错误页面),例如"当前访问人数过多,请稍后重试"

  • 软状态(soft state)

软状态是指运行系统中存在中间状态,而该中间状态不会影响系统的整体可用性,分布式存储中一般一份数据会有多个副本,允许不同副本同步的延时就是软状态

  • 最终一致性(Eventual Consistency)

最终一致是指系统中的所有数据副本经过一定时间后,最终能达到一致的状态,弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况


解决方案

1、2PC模式

2PC模式
注:下面所说数据库也可以理解为每个服务中的事务

  1. 第一阶段

事务管理器要求每个涉及事务的数据库预提交(precommit)此操作,并反映是否可以提交

  1. 第二阶段

事务管理器要求每个数据库提交数据

在2PC模式中,任意一个数据库否决本次提交,那么所有数据库都会被要求回滚他们在此事务中的那部分信息

除了2阶提交协议,还有3阶提交协议,不做详细描述

2、柔性事务-TCC事务补偿型方案

  • 刚性事务:遵循ACID原则,强一致性
  • 柔性事务:遵循BASE原理,最终一致性

与刚性事务不同,柔性事务允许同一时间,不同节点的数据不一致,但要求最终一致。

柔性事务

  • 一阶段 prepare行为:调用自定义的prepare逻辑(也就是准备数据,执行相关业务操作,但是不提交)
  • 二阶段 commit行为:调用自定义的commit逻辑(也就是提交数据)
  • 三阶段 rollback行为:调用自定义的rollback逻辑(也就是回滚数据,回滚之前新增/修改的数据)
    所谓的TCC模式,就是把执行、提交、回滚拆成三个操作,加入到全局事务中

3、柔性事务-最大努力通知型方案

按照规律进行通知,不保证数据一定能够通知成功,提供一个查询接口进行核对。这种方案主要用于和第三方通讯时,比如,调用微信或者支付宝支付成功后,支付宝/微信进行支付结果回调通知。这种方案也可以结合MQ进行实现,例如:通过MQ发送http请求,设置最大通知数,通知后调用查询接口进行核对,核对成功则不继续通知,核对失败则继续通知,一直达到最大通知数。

4、柔性事务-可靠消息+最终一致性方案(异步通知型)

可靠消息:保证消息不会丢失、重复消费、积压
最终一致性:保证数据达到最终一致,不需要强一致性


实现方案

1、 使用SpringCloudAlibaba的Seata组件(不适合高并发场景)

Seata的AT类似于TCC事务补偿方案,只是回滚操作是自动执行,不需要开发人员写业务代码

Seata入门

2、使用延时队列

为什么不使用定时任务轮询数据库?

定时任务会消耗系统内存,增加数据库压力,存在较大的时间误差

1. 延时队列知识点:

延时队列利用的是MQ中的TTL(Time To Live)以及死信

名词介绍:
TTL:消息的存活时间
死信:消息一直到过期都没有消费者消费,就会被丢弃,这种消息称为死信

2. 实现原理:

死信可以设置处理方式,比如丢弃或者设置一个死信路由(注:死信路由,也是一个普通的exchange(交换器)),通过设置死信路由路由的队列,从而实现,消息过期之后,通过死信路由路由到被监听的队列,达到延时队列的效果(重点:延时队列不能被监听!!!

示意图:
延时队列
如果有规范,一个微服务只能有一个交换机,那么可以这样
在这里插入图片描述

问题

1、如何保证消息可靠?

要保证消息可靠性,需要保证消息不会被丢失重复消费积压

1. 消息丢失

消息丢失分为三种情况:

1. 生产者发消息给Broker的时候,由于网络问题,消息发送失败

解决方案

1、做容错方法(try-catch),如果消息发送失败,重新发送消息
2、发送消息时记录日志,保存消息的发送状态,并定期使用定时器扫描日志表,对发送失败的消息进行重新发送

2. 消息到达Broker,在Broker尚未持久化时,Broker宕机,导致消息丢失

解决方案

1、使用消息确认机制,消息到达队列时,调用returnCallback方法,修改消息日志表的状态

在这里插入图片描述

3. 自动ack情况下,消息到达消费者,尚未被消费,消费者宕机,导致消息丢失

解决方案

手动ack

2. 重复消费

这种情况可能发生在消费者已经消费了消息,但是在准备ack时,服务宕机(又或者消费者和mq断开连接),导致消息又回到了队列中,等服务恢复,消息重新发送。

解决方案

使用幂等

3. 积压

大量消息进入队列,而消费者能力有限,导致消息大量积压在队列中,影响mq的性能。
解决方案

1、上线更多消费者进行消费
2、设置专门的队列消费服务,先将所有消息存储到数据库中,然后再离线处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值