当前位置: 首页 > 科技观察

不要说你不知道分布式事务

时间:2023-03-12 03:47:24 科技观察

简介我们都知道Seata是分布式事务的解决方案。今天我们就带大家了解一下什么是分布式事务。首先,了解一下基础知识——事务,我们先来了解一下事务是什么概念。事务的基本概念由四部分组成—ACID:A(Atomic):原子性,所有构成事务的操作要么执行成功要么执行失败,不会有部分成功或部分失败的情况。C(一致性):一致性。事务执行前后,数据库的一致性约束没有被破坏。比如,小勇去银行取100元。提现前是600,提现后应该是400,数据正确,数值一致。如果取出100,但是银行里的钱没有减少,或者小勇要笑醒了,这不符合一致性要求。I(Isolation):隔离。数据库中的事务通常是并发的。隔离是指两个并发事务的执行过程不会相互干扰。一个事务在执行过程中看不到其他事务的中间状态,通过配置事务隔离级别,可以避免脏读、重复读等问题。D(Durability):持久性,当事务完成后,事务所做的数据更改会被持久化到数据库中,不会回滚。事务分为本地事务和分布式事务两部分。本地事务:在计算机系统中,事务多由关系型数据库控制,利用数据库本身的事务特性来实现,因为应用程序主要依赖关系型数据库来维护事务,而数据库和应用程序都在同一个服务器上,所以基于关系数据的事务也称为本地事务。分布式事务:分布式事务是指事务的参与者、支持事务的服务器、资源服务器和事务管理器位于不同分布式系统的不同节点上,属于不同的应用程序。分布式事务需要确保这些操作要么全部成功,要么全部失败。分布式事务是为了保证数据库数据在不同服务器上的一致性。Seata的设计思想是将多个服务器的本地事务合并为一个全局事务。以下本地事务可以满足ACID。最好形成一个完整的分布式事务。操作分布式事务就像操作本地事务一样。分布式系统会将应用程序拆分为多个可独立部署的服务。服务之间通常需要远程协作来完成事务操作。在这种分布式系统环境中,不同服务之间通过网络远程协作完成的交易称为分布式交易,例如在供应链系统中,订单创建(生成订单、扣除库存、交付绩效通知)等。在上图中,我们可以看到,只要涉及到操作多个数据源,就会出现事务问题。我们在实际开发中应该避免这个问题,但是虽然系统在扩展,应用与应用之间的关系难免会有应用与应用之间的事务分离。在微服务架构中,主要有MQ和Seata。在了解它们之前,我们先来了解一下分布式事务是如何组成的,又是如何实现的。分布式事务什么是分布式事务?分布式事务是指事务的参与者、支持事务的服务器、资源服务器位于分布式系统的不同节点上。通常,分布式事务涉及多个数据源或业务系统的操作。随着互联网的发展,以前的单体项目逐渐向分布式服务转变。现在微服务在各个公司都很普遍,那个时候的本地事务已经不能满足分布式应用的要求了。因此,分布式服务之间事务的协调产生了问题。如果多个服务之间的事务操作能像本地事务一样遵循ACID原则,就成了一个难题。然而,在专家们的不断探索下,他们终于发现了分布式事务的存在。两个理论基础:CAP定律和BASE理论。CAP法则CAP法则由一致性(C)、可用性(A)和分区容错性(P)组成。在分布式系统中,不可能同时满足Consistency(一致性)/Availability(可用性)/Partitiontolerance(分区容错性)三个特性,最多同时满足其中两个。一致性(C):分布式系统中所有数据备份同时一致,所有应用节点访问同一个最新的数据副本。可用性(A):当集群中部分节点发生故障时,集群整体能够响应客户端的读写请求,对数据更新具有高可用性。分区容错(P):如果系统不能在规定的时限内实现数据一致性,则意味着将发生分区。当前的操作需要在C和A之间进行选择,这样系统在遇到网络故障等待的情况下,仍然可以保证对外提供满足一致性或可用性要求的服务。上图中我们可以看到,当我们的用户去购物车点击下单结算的时候,会先通过我们的库存服务判断库存是否充足。当库存充足并扣减库存后,我们需要将数据同步到其他服务器上,这一步是为了保证数据结果的一致性。如果此时网络有波动,我们的系统需要保证分区容错,也就是我们要容忍一些网络带来的问题。这个时候我们要保证一致性就需要放弃可用性。但是,为了保证高可用,在高并发的情况下,是不可能保证在限定时间内响应的。由于网络的不可靠性,我们的订单服务可能无法获取最新的数据,但我们不得不为用户做这件事。如果没有响应,那么就不能保证一致性,所以AP不能保证强一致性。如果要同时保证高可用和一致性,必须在网络好的情况下实现,那么解决方案只有一个,就是要把库存、订单、性能放在一起,但这取决于我们的微观服务的角色不再是分布式系统。在分布式系统中,分区容错是必须存在的,我们只能在一致性和可用性之间做出选择。在这种情况下,BASE理论诞生了。BASE理论BASE由三个部分构成:基本可用、软状态和最终一致。它是CAP中一致性和可用性之间权衡的结果。实践的总结是在CAP定理的基础上逐步演化而来的。核心四大系统无法及时实现强一致性,但各个应用可以根据自身业务特点采用合适的方法使系统实现最终一致性。.基本可用性:基本可用性是指当分布式系统发生不可预知的故障时,允许损失部分可用性,但这并不意味着系统不可用,主要体现在以下几点:响应时间的损失,在正常情况下,在线搜索引擎需要在0.5秒内将查询结果返回给用户,但由于故障,查询结果的响应时间增加了1-2秒。系统功能的丧失。一般情况下,消费者在电子商务网站购物时,几乎可以顺利完成每一个操作。为保证系统的稳定性,部分消费者可能会被引导至页面或提示进行临时降级处理。基本可用是指我们的核心服务可以使用,其他服务可以适当减少响应时间,甚至进行服务降级处理。在当前环境下,库存和订单绝对是核心服务。至于我们的交付,只要当时系统基本可用,它的同步可以慢一点,也可以延迟高一点,等流量高峰过后就可以恢复了。Softstate:Softstate是指允许系统中的数据有一个中间状态,并且认为这个中间状态的存在不会影响系统整体的可用性,即存在延迟无节点系统的数据副本之间的数据同步过程。软态就是当我们大量下单,扣库存的时候,流量暴增。此时,如果大量访问库存或订单,系统可能会被破坏。在这个过程中,我们可以让数据同步有一个不影响整体系统使用的延迟。最终一致性:最终一致性强调的是所有的数据副本经过一段时间的同步后,最终能够达到一致的状态。所以,最终一致性的本质是需要系统保证最终数据能够一致,而不是需要实时保证系统的强一致性。流量高峰期过后,经过一段时间的同步,中间状态最终成为最终的数据一致性,保证各业务数据的一致性。两阶段提交(2PC)2PC是两阶段提交协议,将整个事务过程分为两个阶段,P指准备阶段,C指提交阶段。就像我们去KCC买雪糕,刚好有活动,第二杯半价,但是你一个人,这时候过来一个小姐姐正在考虑要不要买雪糕,at这次你跟她提出AA,也就是说,只有你和她都同意买这个,你才能买。如果两个人中有一个不同意,那么你就不能买这个冰淇淋了。第一阶段:准备阶段。老板让你先付款。你同意完成付款后,再让女方付款,女方同意完成付款。Phase2:提交阶段支付完成,老板开饭,两人吃冰淇淋。这个例子构成了一个交易。如果其中一男一女拒绝付钱,老板就不会开饭,并退还所收的钱。整个交易过程由交易管理者和参与者组成。店主是交易的管理者,你和姑娘是参与者。事务管理器对整个分布式事务进行决策。计算机中的关系数据支持两阶段提交协议:准备阶段(Preparephase):事务管理器向每个参与者发送Prepare消息,每个数据库参与者在本地执行事务并写入本地Undo/Redo日志。此时,事务未提交。undolog记录修改前的数据,用于数据库回滚。重做日志是记录修改的数据,用于提交事务,写入数据文件。提交阶段:如果事务管理器收到某个参与者的执行失败或超时消息,它会直接向每个参与者发送(Rollback)消息。如果成功接收到所有参与者,则发送(Commit)参与者根据事务管理器的指令执行提交或回滚操作,释放事务过程中使用的资源。提交成功:事务管理器将事务内容发送给所有参与者,询问是否就绪,等待参与者的响应,每个参与者事务节点执行事务操作,并在事务日志中记录Undo和Redo信息。如果参与者成功执行交易操作,将反馈交易管理器的YES操作,表示交易可以执行。如果协调器收到所有参与者的Yes响应,则将执行事务提交。失败:如果任何参与者向事务管理器反馈No指令,或者等待超时后,事务管理器无法收到所有参与者的反馈响应,则中断事务,发送回滚请求,事务管理器发送向所有参与者请求节点发送回滚请求。参与者收到回滚请求后,将使用第一阶段记录的Undo信息来执行事务的回滚操作。回滚完成后,释放事务执行过程中占用的资源。参与者完成事务回滚后,向协调器发送ACK消息,事务管理器收到所有参与者反馈的ACK消息后,完成事务中断。三阶段提交(3PC)3PC主要是为了解决两阶段提交协议的单点故障问题,减少参与者阻塞的范围。它是两阶段提交(2PC)的改进版本。3PC除了引入参与节点的超时机制外,还将2PC的准备阶段分为交易查询(该阶段不会阻塞)和交易预提交。三个阶段分别是CanCommit和PreCommit、DoCommit。CanCommit查询状态Coordinator在CanCommit阶段会向Participant发送CanCommit消息,询问是否可以执行操作。参与者收到消息后,表明可以执行操作,并会向协调器返回一个可以执行的命令(yes)。如果参与者不能执行,则返回No命令,释放资源,交易结束。PreCommit预提交PreCommit阶段如果协调器收到参与者返回的状态值为YES,证明他们都有能力执行这个操作,那么协调器会向所有参与者发送PreCommit消息,协调器收到PreCommitmessage之后,再回去执行本地事务。如果执行成功,会保存本地事务undo和redo,然后返回给coordinatorYES命令。如果本地事务执行失败,会返回协调器号。只要协调器收到执行失败,就会向所有参与者发送中断事务消息,参与者收到消息后回滚事务。在这个阶段,参与者和协调者都引入了超时机制。如果参与者没有收到协调器的消息,或者协调器没有收到参与者返回的预执行结果状态,交易将在等待超时后中断。避免事务阻塞。协调器向参与者发送PreCommit,如果参与者执行成功则返回yes。如果参与者执行失败,只有一个会返回No给协调器,协调器会向参与者发送消息中断事务,参与者回滚事务。DoCommit提交协调器收到所有参与者的YES。这个时候协调者会向所有参与者发送DoCommit。参与者收到DoCommit后,才会真正提交事务。当事务提交成功后,会返回协调器的YES状态,表示我已经完成了事务的提交。协调器收到所有参与者的YES状态后,事务完成。如果参与者返回No消息,协调者向参与者发送中止事务消息(abort),参与者回滚事务。3PC是2PC的升级版,引入了超时机制来解决单点故障导致的事务阻塞问题,但是3PC仍然不能解决事务一致性问题,因为在DoCommit阶段,如果网络或者超时原理导致participanttoreceive协调者发送的中止事务消息(abort)没有收到。在此时间之后,参与者将提交交易。它应该回滚。事务提交后,会出现数据不一致的问题。虽然2PC在网络故障的情况下,存在强一致性被破坏的问题,但是故障恢复后最终一致性是可以保证的。3PC虽然有超时时间,解决了阻塞,提高了可用性,但是牺牲了一致性。如果网络波动问题导致数据出现问题,这一点上,2PC优于3PC。Seata官网:https://seata.io/zh-cn/docs/overview/what-is-seata.html。Seata是一个开源的分布式事务解决方案,致力于提供高性能易用的分布式事务服务。Seata将为用户提供AT、TCC、SAGA和XA交易模式,为用户打造一站式的分布式解决方案。在微服务体系中,一般的业务都会拆分成独立的模块。在官方的结构图中,我们可以看到目前分为三个模块。库存服务:对商品库存信息进行增减操作。订单服务:根据用户指定的商品生成订单。账户服务:从用户账户中扣除余额、添加积分、维护地址信息等。在当前的架构中,用户选择了想要的商品并下单后,需要三个服务来完成操作。每个服务内部都有一个独立的本地事务来保证当前服务数据的强一致性,但是三个服务组成的全局事务一致性是没有办法保证的,所以Seata就是来解决这个问题的。Seata术语官网地址:https://seata.io/zh-cn/docs/overview/terminology.html。在了解Seata之前,我们先来了解一下Seata的几个关键概念:TC(TransactionCoordinator)事务协调器:维护全局事务和分支事务的状态,驱动全局事务的提交或回滚。TM(TransactionManager)事务管理器:发起者,RM的一种,定义全局事务的范围,启动全局事务,提交或回滚全局事务。RM(ResourceManager)资源管理器:参与事务的微服务,为分支事务管理资源,与TC对话注册分支事务并报告分支事务状态,驱动分支事务提交或回滚。Seata2PC第一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。阶段2:提交是异步的并且完成得非常快。回滚通过单阶段回滚日志进行反向补偿。在第一阶段提交本地事务之前,您需要确保首先获得全局锁。没有全局锁,本地事务无法提交。获取全局锁的尝试被限制在一定范围内,超过范围则放弃,回滚本地事务,释放本地锁。基于数据库本地事务隔离级别readcommitted或以上,Seata(AT模式)默认的全局隔离级别是readuncommitted。如果应用在特定场景下使用,则必须要求全局读提交。目前的Seata方法是通过SELECTFORUPDATE语句的代理。Seata执行流程分析:每个RM使用DataSourceProxy链接数据路径,目的是使用ConnectionProxy,使用数据源和数据代理的目的是在第一阶段在本地事务中提交undo和业务数据,使其只要有业务操作的dudo日志就可以保存。第一阶段,undo存储数据修改前后的修改值,为事务回滚做准备。第一阶段完成后,分支事务已经提交,锁资源被释放。TM启动全局事务,将XID全局事务ID放入事务上下文中,通过feign调用将XID传给下游服务器。每个分支事务将其自己的分支ID与XID相关联。在全局交易提交的第二阶段,TC会通知每个分支参与者提交分支交易。第一阶段已提交分行交易。这里每个参与者只需要删除undo,可以异步执行。如果某个分支事务异常,在全局事务回滚操作的第二阶段,TC会通知各个分支参与者回滚该分支事务,通过XID和Branch-ID找到对应的回滚日志,并使用生成的反向日志通过回滚日志SQL执行,分支事务完成后回滚到之前的状态。Seata下载安装下载地址:https://github.com/seata/seata/releases。解压后找到conf目录。在我们启动seata之前,我们需要先启动nacos。其实很简单。你只需要下载nacos并启动它。如果您不知道如何操作nacos,请参考nacos基础介绍。下载seata-server.bat。如果我们看到8091端口正在监听,并且看到服务已经注册到nacos中,就说明我们的seata启动成功了。综上所述,我们对分布式事务和seata的介绍到这里就结束了。其实对于分布式事务和MQ实现可靠的消息最终一致性,MQ主要解决两个功能:本地事务的原子性和消息发送。交易参与者接收消息的可靠性。