前言最近看了几篇关于分布式事务的博文,做了笔记。哈哈~数据库事务数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单元。它由有限的数据库操作序列组成。这些操作要么被执行,要么根本不执行。这是一部不可分割的作品。单元。数据库事务的几个典型特征:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durabilily),简称ACID。原子性:事务作为一个整体执行,包含在其中的对数据库的操作要么全部执行,要么都不执行。一致性:表示在事务开始前和事务结束后数据都不会被破坏。如果A账户向B账户转10元,无论成功与否,A和B的总金额不变。隔离性:当多个事务并发访问时,事务之间是相互隔离的,即一个事务不影响其他事务的运行效果。简而言之,就是事与愿违,水到渠成。持久化:事务完成后,事务对数据库所做的操作改变会被持久化到数据库中。事务的实现原理本地事务传统的单服务器、单关系数据库事务都是本地事务。本地事务由资源管理器管理,JDBC事务是一种非常典型的本地事务。事务日志InnoDB事务日志包括redolog和undolog。重做日志(redolog)重做日志通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行是如何被修改的。用于恢复提交的物理数据页。undolog(回滚日志)undolog是一种逻辑日志,它不同于redolog记录的物理日志。可以认为,当一条记录被删除时,undolog中会记录一条对应的insert记录,当一条记录被更新时,会记录一条对应的update记录。事务ACID特性原子性的实现思路:利用undolog实现。如果事务执行过程中出现错误或者用户执行了回滚,系统会通过undolog日志返回事务的状态。持久化:使用redolog来实现,只要redolog日志是持久化的,当系统崩溃时,可以通过redolog恢复数据。隔离性:通过锁和MVCC,事务之间相互隔离。一致性:一致性是通过并发下的回滚、恢复、隔离来实现的。分布式事务分布式事务:是指事务的参与者、支持事务的服务器、资源服务器和事务管理器分别位于不同分布式系统的不同节点上。简单的说,分布式事务是指分布式系统中的事务,它的存在是为了保证不同数据库节点的数据一致性。为什么需要分布式事务?接下来分两个方面进行讲解:微服务架构下的分布式事务随着互联网的飞速发展,轻量级、功能分工明确的微服务走上了历史舞台。比如一个用户下单购买直播礼物的服务,拆分成三个服务,分别是coinService、orderService、giftService。这些服务部署在不同的机器(节点)上,相应的数据库(金币库、订单库、礼物库)也在不同的节点上。当用户下单购买礼物时,礼物库、金币库和订单库在不同的节点上。无法使用本地事务,那么如何保证不同数据库(节点)上的数据一致性呢?这就需要分布式事务了~分库分表下的分布式事务随着业务的发展,数据库中的数据越来越大,超过千万级的数据,我们需要分库分表tableforit(公司以前用mycat分库分表,后来用sharding-jdbc)。在子数据库中,数据分布在不同的节点上。比如有的在深圳机房,有的在北京机房~如果要用本地事务来保证,已经无所谓了~还是需要分布式事务。比如A转10元给B,A的账户数据在北京机房,B的账户数据在深圳机房。过程如下:CAP理论&BASE理论学习分布式事务,当然需要了解CAP理论和BASE理论。CAP理论,作为分布式系统的基础理论,是指在分布式系统中,Consistency(一致性)、Availability(可用性)、Partitiontolerance(分区容错),这三个要素只能同时实现最多两点。一致性(C:Consistency):一致性是指数据在多个副本之间能否保持一致。例如,某个分区节点上更新了一条数据后,从其他分区节点读取的数据也是更新后的数据。可用性(A:Availability):可用性是指系统提供的服务必须始终可用,用户的每次操作请求总能在限定的时间内返回结果。这里的重点是“限时”和“返回结果”。分区容忍度(P:Partitiontolerance):当分布式系统遇到任何网络分区故障时,仍然需要能够对外提供满足一致性和可用性的服务。选择表明CA放弃了分区容错,加强了一致性和可用性。其实就是传统单机数据库的选择。AP放弃了一致性、分区容错和可用性。这是很多分布式系统设计的选择。CP放弃可用性,追求一致性。而分区容错,网络问题会直接导致整个系统不可用。BASE理论BASE理论是AP在CAP中的延伸。对于我们的业务系统,我们考虑牺牲一致性来换取系统可用性和分区容错性。BASE是BasicallyAvailable(基本可用)、Softstate(软状态)和Eventuallyconsistent(最终一致性)这三个短语的首字母缩写。基本可用:它是通过支持本地故障而不是系统范围的故障来实现的。例如,如果用户被分区在5个数据库服务器上,一个用户数据库的故障只会影响这台特定主机上20%的用户,而其他用户不会受到影响。SoftState软状态,状态可以在一段时间内不同步EventuallyConsistent,最终数据是一致的,而不是一直保持强一致性。分布式事务的几种解决方案分布式事务解决方案主要有以下几种:2PC(two-phasecommit)方案TCC(Try,Confirm,Cancel)本地消息表besteffortnotificationSagatransactiontwo-phasecommitschemetwo-phasecommitScheme是一种比较常用的方案使用分布式事务解决方案。事务的提交分为两个阶段:准备阶段和执行计划的提交。在两阶段提交成功的情况下,在准备阶段,事务管理器向各个资源管理器发送准备消息,如果资源管理器的本地事务操作执行成功,则返回成功。在commit执行阶段,事务管理器如果收到所有资源管理器的成功消息,就会向各个资源管理器发送commit消息,RM根据TM的指令执行commit。如图:在准备阶段,事务管理器向各个资源管理器发送准备消息。如果资源管理器的本地事务操作执行成功,则返回success,执行失败则返回failure。在提交执行阶段,如果事务管理器收到任何资源管理器失败的消息,它会向每个资源管理器发送回滚消息。资源管理器根据事务管理器的指令回滚本地事务操作,释放事务过程中使用的所有锁资源。两阶段提交的优缺点2PC方案实现简单,成本低,但主要有以下缺点:单点问题:如果事务管理器发生故障,资源管理器将一直处于锁定状态。性能问题:事务提交阶段所有资源管理器都处于同步阻塞状态,占用系统资源,直到提交完成才释放资源,容易造成性能瓶颈。数据一致性问题:如果有的资源管理器收到了提交的消息,有的没有收到,就会导致数据不一致。TCC(补偿机制)TCC采用补偿机制,其核心思想是:对于每一个操作,都要注册一个相应的确认和补偿(撤销)操作。TCC(Try-Confirm-Cancel)模型TCC(Try-Confirm-Cancel)通过分解业务逻辑实现分布式事务。对于一个具体的业务服务,TCC分布式事务模型需要业务系统实现以下三块逻辑:try阶段:尝试执行,完成所有业务的一致性校验,并预留必要的业务资源。Confirm阶段:该阶段业务确认提交,不做任何检查,因为try阶段已经检查过了,默认的Confirm阶段是不会出错的。Cancel阶段:如果业务执行失败,进入该阶段,释放try阶段占用的所有业务资源,回滚Confirm阶段执行的所有操作。TCC分布式事务模型包括三部分:主业务服务、从业务服务、业务活动管理器。主业务服务:主业务服务负责发起和完成整个业务活动。从业务服务:从业务服务是整个业务活动的参与者,实现了Try、Confirm、Cancel等操作,被主业务服务调用。业务活动管理器:业务活动管理器对整个业务活动进行管理和控制,包括记录交易状态,从业务服务中调用Confirm操作,从业务服务中调用Cancel操作等。我们以用户下单购买礼物为例举例模拟TCC的分布式交易过程:假设用户A的余额为100金币,有5件礼物。A花费10金币下单,购买10朵玫瑰。余额、订单、礼物都在不同的数据库中。TCC的Try阶段:生成订单记录,订单状态为待确认。更新用户A账户金币余额为90,冻结金币为10(预留业务资源)设置用户赠送数量为5,预增数量为10,Try成功后进入Confirm阶段。Try过程出现任何异常都会进入Cancel阶段TCC的Confirm阶段:订单状态更新为已支付,用户余额更新为90,可冻结为0。用户赠送数量更新为15,前置增量为0。如果Confirm过程中出现异常,则进入Cancel阶段。如果Confirm流程执行成功,交易将结束TCCCancel阶段:修改订单状态为cancel更新用户余额为100更新用户赠送数量为5TCC优缺点TCC方案允许自定义应用粒度数据库操作减少了锁冲突,可以提高性能,但也有以下缺点:应用程序侵入性强,try、confirm、cancel三个阶段都需要业务逻辑来实现。需要根据网络、系统故障等不同的故障原因,实施不同的回滚策略,实施难度大。一般使用TCC开源框架,ByteTCC,TCC-transaction,Himly。本地消息表eBay最初提出本地消息表方案是为了解决分布式事务问题。业界目前较多采用这种方案,其核心思想是将分布式事务拆分成本地事务进行处理。可以看看基本实现流程图:基本实现思路消息的发送方:需要有一个消息表,记录消息状态的相关信息。业务数据和消息表在同一个数据库中,即必须在同一个本地事务中。在本地事务处理完业务数据并写消息表操作后,将消息写入MQ消息队列。消息将发送给消息消费者。如果发送失败,将重试。消息消费者:处理消息队列中的消息,完成自己的业务逻辑。此时如果本地事务处理成功,说明处理成功。如果本地事务失败,则重试执行。如果是业务失败,则向消息生产者发送业务补偿消息,通知回滚等操作。生产者和消费者定期扫描本地消息表,重新发送未处理的消息或失败的消息。如果有靠谱的自动对账和补货逻辑,这个方案还是很实用的。优缺点:该方案的优点是很好的解决了分布式事务问题,实现了最终一致性。缺点是消息表会和业务系统耦合。BestEffortNotification什么是MaximumNotificationBestEffortNotification也是一种分布式事务解决方案。以下为企业网银转账示例。企业网银系统调用前台接口,跳转到转账页面。企业网银调用转账系统接口。转账系统完成转账流程,并向企业网银系统发起转账结果通知。重复通知。如果企业网银系统没有收到通知,会主动调用转账系统接口查询转账结果。遇到汇款退款等情况,转账系统会定期回来进行对账。尽力而为通知方案的目标是发起通知者使用一定的机制尽量将业务处理结果通知给接收者。best-effort通知的实现机制如下:best-effort通知解决方案实现best-effort通知,可以使用MQ的ack机制。场景一、发起方向MQ发送通知。2、接收方监听MQ消息。3、通知方收到消息后,业务处理完毕,回复ack。4、如果接收方没有回复ack,MQ会每隔1min、5min、10min等重复一次通知。5、接收通知的一方可以使用消息校对接口来保证消息的一致性。转账业务实现流程图:交互过程如下:1.用户请求转账系统进行转账。2、转账系统完成转账,将转账结果发送给MQ。3、企业网银系统监控MQ,收到转账结果通知。如果收不到消息,MQ会重复发送通知。收到转账结果后,更新转账状态。4、企业网银系统还可以主动查询转账系统的转账结果查询界面,更新转账状态。Saga交易Saga交易由普林斯顿大学的HectorGarcia-Molina和KennethSalem提出。它的核心思想是将一个长事务拆分成多个本地短事务,由Saga事务协调器协调。如果正常结束,则正常完成。如果某个If步骤失败,则以相反的顺序一次调用一个补偿操作。saga简介Saga=LongLiveTransaction(LLT,长寿事务)LLT=T1+T2+T3+...+Ti(Ti是本地短事务)每个本地事务Ti都有对应的补偿CiSaga的执行顺序是正常的:T1T2T3...Tn异常情况:T1T2T3C3C2C1Saga向后恢复。如果任何本地子交易失败,补偿已完成的交易。例如异常情况的执行顺序为T1T2TiCiC2C1。前向恢复,即重试失败的交易,假设每个子交易最终都会成功。执行顺序:T1,T2,...,Tj(失败),Tj(重试),...,Tn。例如,假设用户下单,花费10元买了10多朵玫瑰,则T1=下单,T2=扣用户10元,T3=给用户加10朵玫瑰,T4=减去10朵玫瑰从库存C1=取消订单,C2=给用户加10元,C3=给用户减去10朵玫瑰,C4=给库存加10朵玫瑰假设交易执行到T4发生异常回滚,当C4准备将玫瑰添加回库存,发现用户的玫瑰全部用完了。这是Saga的一个缺点,是事务之间没有隔离性造成的。
