目录
基础概念
本地事务
分布式事务
基础理论
CAP理论
BASE理论
分布式事务解决方案
2PC
TCC
可靠消息最终一致性
在计算机系统中,更多的是通过关系型数据库来控制事务,这是利用数据库本身的事务特性来实现的,因此叫数据 库事务,由于应用主要靠关系数据库来控制事务,而数据库通常和应用在同一个服务器,所以基于关系型数据库的 事务又被称为本地事务。
回顾一下数据库事务的四大特性 ACID :A ( Atomic ) :原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失败的情况。C ( Consistency ) :一致性,在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转 100 元,转账前和转账后的数据是正确状态这叫一致性,如果出现张三转出 100 元,李四账户没有增加 100 元这就出现了数据错误,就没有达到一致性。I ( Isolation ) :隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事务不能看到其他事务运行过程的中间状态。通过配置事务隔离级别可以避脏读、重复读等问题。D ( Durability ) :持久性,事务完成之后,该事务对数据的更改会被持久化到数据库,且不会被回滚。数据库事务在实现时会将一次事务涉及的所有操作全部纳入到一个不可分割的执行单元,该执行单元中的所有操作要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚
随着互联网发展越来越快,软件项目也随之越来越大,此时之前的单体服务演变至今的微服务分布式架构。
分布式系统会把一个应用系统拆分为可独立部署的多个服务,因此需要服务与服务之间远程协作才能完成事务操作,这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例如用户注册送积分 事务、创建订单减库存事务,银行转账事务等都是分布式事务。
CAP是 Consistency、Availability、Partition tolerance三个词语的缩写,分别表示一致性、可用性、分区容忍性。
- C - Consistency:
一致性是指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意结点读取到的数据都是最新的状态。上图中,商品信息的读写要满足一致性就是要实现如下目标:1 、商品服务写入主数据库成功,则向从数据库查询新数据也成功。2 、商品服务写入主数据库失败,则向从数据库查询新数据也失败。如何实现一致性?1 、写入主数据库后要将数据同步到从数据库。2 、写入主数据库后,在向从数据库同步期间要将从数据库锁定,待同步完成后再释放锁,以免在新数据写入成功后,向从数据库查询到旧的数据。 分布式系统一致性的特点:1 、由于存在数据同步的过程,写操作的响应会有一定的延迟。2 、为了保证数据一致性会对资源暂时锁定,待数据同步完成释放锁定资源。3 、如果请求数据同步失败的结点则会返回错误信息,一定不会返回旧数据。
- A - Availability :
可用性是指任何事务操作都可以得到响应结果,且不会出现响应超时或响应错误。上图中,商品信息读取满足可用性就是要实现如下目标:1 、从数据库接收到数据查询的请求则立即能够响应数据查询结果。2 、从数据库不允许出现响应超时或响应错误。如何实现可用性?1 、写入主数据库后要将数据同步到从数据库。2 、由于要保证从数据库的可用性,不可将从数据库中的资源进行锁定。3 、即时数据还没有同步过来,从数据库也要返回要查询的数据,哪怕是旧数据,如果连旧数据也没有则可以按照约定返回一个默认信息,但不能返回错误或响应超时。分布式系统可用性的特点:1 、 所有请求都有响应,且不会出现响应超时或响应错误。
- P - Partition tolerance :
通常分布式系统的各各结点部署在不同的子网,这就是网络分区,不可避免的会出现由于网络问题而导致结点之间通信失败,此时仍可对外提供服务,这叫分区容忍性。上图中,商品信息读写满足分区容忍性就是要实现如下目标:1 、主数据库向从数据库同步数据失败不影响读写操作。2 、其一个结点挂掉不影响另一个结点对外提供服务。如何实现分区容忍性?1 、尽量使用异步取代同步操作,例如使用异步方式将数据从主数据库同步到从数据,这样结点之间能有效的实现松耦合。2 、添加从数据库结点,其中一个从结点挂掉其它从结点提供服务。分布式分区容忍性的特点:1 、分区容忍性分是布式系统具备的基本能力。
由此可以看出,CAP理论在实际项目中只能满足其中两种,实际开发过程中,为了达到更快的响应,一般会放弃C一致性,保留AP
BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩 写。BASE理论是对CAP中AP的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证 核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE理论的事务,我们称之为“柔性事务”。
不要求立即保持一致,但最终的效果是一致的,例如:手机银行转账后的五四三二一倒计时,就是典型的柔性事务。
2PC即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase),2是指两个阶段,P是指准备阶段,C是指提交阶段。
举例:生活中俩人A和B去吃饭,AA制,去交钱的时老板要求A支付一半的费用,A支付,老板要求B支付。此时如果一个人没有支付的话。这顿饭就吃不成了,老板就会把另一个人已经支付的退给他。
常见的方案有:XA方案,阿里的Seate方案(多了个事务协调器)
XA:会把资源进行锁定,占用了资源,一定程度上影响了效率。
Seate:每个服务中都会有个udolog日志表,记录事务之前的日志信息,例如
update order set number = number - 1 where id = 1
回滚的的时候:update order set number = number + 1 where id = 1 即可,不会占用资源。
Seate方案与传统的2pc方案的区别
架构层次方面,传统2PC方案的 RM 实际上是在数据库层,RM 本质上就是数据库自身,通过 XA 协议实现,而 Seata的 RM 是以jar包的形式作为中间件层部署在应用程序这一侧的。 两阶段提交方面,传统2PC无论第二阶段的决议是commit还是rollback,事务性资源的锁都要保持到第二次提交完成 才释放。而Seata的做法是在第一次请求就将本地事务提交,这样就可以省去第一次到第二次提交 持锁的时间,整体提高效率。
...没仔细了解过。市场上有对tcc 事务支持的框架。例如hmily
大家伙感兴趣的百度一下吧。
可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能 够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致。
目前此解决方案都会介入消息队列来进行完成。
前提是保证消息的可靠性。
rabbitmq进阶:回调函数之确认(confirm)模式、回退(return)模式_Fighter-CSDN博客_rabbitmq回调函数一、确认(confirm)模式运用场景当生产方发送消息至交换机后的处理逻辑包括发送成功或者失败废话不多说,直接上代码开启确认模式spring: rabbitmq: host: localhost port: 5672 username: guest password: guest virtual-host: / listener: simple: acknowledge-mode: manual # 消费者https://blog.csdn.net/weixin_44912855/article/details/110872819?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163843179216780255270244%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163843179216780255270244&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29_name-4-110872819.pc_v2_rank_blog_default&utm_term=rabbitmq&spm=1018.2226.3001.4450rabbitmq 消息确认机制ACK_Fighter-CSDN博客概述在使用RabbitMQ的时候,我们可以通过消息持久化操作来解决因为服务器的异常奔溃导致的消息丢失,除此之外我们还会遇到一个问题,当消息的发布者在将消息发送出去之后,消息到底有没有正确到达broker代理服务器呢?如果不进行特殊配置的话,默认情况下发布操作是不会返回任何信息给生产者的,也就是默认情况下我们的生产者是不知道消息有没有正确到达broker的,如果在消息到达broker之前已经丢失的话,持久化操作也解决不了这个问题,因为消息根本就没到达代理服务器,你怎么进行持久化,那么这个问题该怎么解决呢?https://blog.csdn.net/weixin_44912855/article/details/110528362?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163843179216780255270244%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163843179216780255270244&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29_name-2-110528362.pc_v2_rank_blog_default&utm_term=rabbitmq&spm=1018.2226.3001.4450
低版本的消息队列有的可能不支持事务。
俩种方案。
不支持事务的会引入本地消息表,定时任务扫描,经过第一步消息已经写到消息日志表中,可以启动独立的线程,定时对消息日志表中的消息进行扫描并发送至消息 中间件,在消息中间件反馈发送成功后删除该消息日志,否则等待定时任务下一周期重试。
支持事务的消息队列,直接采用其事务机制,保证消息一定会发送成功,例如:rabbitmq的 confirm模式,rocketmq的回调确认机制。
处于综合考虑,大多数企业对于分布式事务技术选型都会采用可靠消息一致性吧。因为在分布式系统中,消息队列基本都会进入。而为了解决事务问题,引入seate(单独服务),难免会增加系统的复杂性。