1.事务的ACID原子性(Atomicity)可以理解为事务内的所有操作要么执行要么不执行。一致性可以理解为满足完整性约束的数据,即不会有中间数据。比如你账户里有400,我账户里有100,你给我200元。这时候你账户里的钱应该是200,我账户里的钱应该是300,不会出现我账户里的钱已经加完你账户里的钱还没有扣的中间状态。隔离性是指多个事务并发执行时不会相互干扰,即一个事务内部的数据与其他事务隔离。持久性是指事务完成后,数据被永久保存,后续的其他操作或失败不会影响事务的结果。2.Redis事务Redis事务不能保证所有的操作要么执行要么不执行。如果Redis事务中的一条命令失败,后续的命令仍然会被处理,Redis不会停止这条命令,也就是不会回滚。Redis认为,如果命令错误是语法错误,应该在开发的时候检测出来,不应该出现在生产环境中。回滚不能避免编程错误。3.2PC是一种强一致性设计,引入事务协调器的角色来协调和管理每个参与者(也称为每个本地资源)的提交和回滚。两个阶段是指准备(投票)和Commit两个阶段正常情况准备阶段:协调者会向每个参与者发送准备命令,了解除了提交交易外其他都已完成。同步等待所有资源的响应,进入提交阶段。提交阶段:协调器向所有参与者发送提交事务命令(提交事务或回滚事务),然后等待所有事务提交成功,然后返回事务执行成功。异常情况如果一个参与者在准备阶段失败,协调器会向所有参与者发送回滚事务的请求,即分布式事务执行失败。第二阶段是回滚交易操作,所以答案是不断重试,直到所有参与者都回滚,否则那些在第一阶段准备成功的参与者将一直被阻塞。第二阶段是执行提交交易操作,那么答案就是不断重试,因为有可能部分参与者的交易已经提交成功。这个时候只有一个办法,就是往前冲,一直重试,直到提交成功。结果,真的不行。协调器可以人工介入处理故障分析2PC是一种同步阻塞协议。协调器有一个超时机制。协调器是单点的,存在单点故障问题。coordinator在发送prepare命令前就挂了,事务没有启动,对coordinator发送没有影响。准备命令挂掉后,事务资源被锁定,事务无法执行,其他操作被阻塞。协调器在发送回滚事务命令前挂掉,事务无法继续提交。第一阶段准备成功的参与者全部??阻塞协调器在发送回滚事务命令后如果挂掉,则大概率回滚成功,释放资源。但是,如果出现网络分区问题,部分参与者会因为接收不到命令而阻塞协调器。协调器在发送committransaction命令前挂掉,资源被阻塞。coordinator发送committransaction命令后挂掉,大概率回滚成功,释放资源。但是,如果出现网络分区问题,部分参与者会因为无法接收命令而阻塞。新的协调员是通过选举产生的。状态推断挂起参与者的状态。在极端情况下,无法避免数据不一致的问题。总结一下同步阻塞。尽量保证强一致性。分布式事务整体效率低下,存在单点故障问题。在极端情况下存在数据不一致的风险,无法实现数据一致性,需要补偿机制。4.3PC还引入了参与者之间的超时机制CanCommit、PreCommit、DoCommit。正常准备阶段:查询参与者状态,加载预提交阶段:同2PC准备阶段提交阶段:同2PC提交阶段。好处是不会直接锁资源,而是先询问情况,加入超时机制。如果等待预提交命令超时,那就做该做的事。如果等待提交命令超时,那么参与者Commit事务就会多一个阶段的劣势,性能也会变差。在大多数情况下,资源是可用的。超时机制仍然存在数据不一致的问题。比如在等待commit命令超时时,参与者默认执行的是提交事务操作,但是有可能执行的是回滚操作,所以数据不一致。总结引入预提交阶段来统一参与者之间的状态。如果调度器挂了,新的协调器来的时候发现有一个参与者处于预提交或者提交阶段,说明所有的参与者都已经确认了,所以这个时候执行commit命令。引入了参与者超时机制,但整体交互过程较长,性能有所下降,仍然存在数据不一致的问题。因为无法确定被挂断的参与者是否执行了交易。需要补偿机制5.TCCTCCTry指的是reservation,即资源的预留和锁定。请注意,这是预订。Confirm指的是确认操作,这一步其实才是真正的执行。取消指的是撤销操作,可以理解为取消预定阶段的动作。TCC在思想上类似于2PC,是通过代码人工实现的两阶段提交。TCC模型还有事务管理器的作用,变成多点,引入集群。用于记录TCC全局事务状态,提交或回滚事务引入超时,超时后补偿,不会锁住整个资源。优势TCC可以实现跨数据库和不同业务系统的交易。缺点TCC对业务和业务的侵入性大紧耦合的撤销和确认操作的执行可能需要重试,因此需要保证操作的幂等性。6、本地消息表利用各个系统的本地事务实现分布式事务。本地消息有一张表,一般是放在数据库中,然后在执行业务的时候,把业务的执行和放消息的操作放到同一个事务中的消息表中,保证将消息放入本地表的业务必须是一个成功的后台任务,定时读取本地的消息表,过滤掉不成功的消息然后调用相应的服务,服务更新成功后改变消息的状态.重试必须保证对应服务的方法是幂等的,一般会有最大重试次数。如果超过最大重试次数,可以记录告警,允许人工处理以达到最终一致性。7、消息事务使用MQ事务先发送给Broker事务性消息是半消息,半消息不是半消息,而是这个消息对消费者是不可见的,然后发送者发送后执行本地事务成功,然后根据本地事务的结果向Broker发送Commit或者RollBack命令。RocketMQ发送端会提供一个接口来反向查询交易状态。如果半消息在一段时间内没有收到任何操作请求,Broker会通过反向检查接口知道发送方的交易是否执行成功,然后执行Commit或RollBack命令。如果是Commit,那么订阅者就可以收到这条消息,然后做相应的操作,做完之后再消费这条消息。如果是RollBack,那么订阅者是收不到这条消息的,也就是说事务还没有执行。消息事务也实现了最终一致性8.通知本地消息表的besteffort也可以算作besteffort,事务消息也可以算作besteffort。besteffortnotification其实只是展示了灵活交易的思想:我已经尽力达成了交易的最终协议。适用于时间不敏感的业务,如短信通知。9、Saga长期事务解决方案更适合“业务流程长、业务流程多”的场景,尤其是参与事务的服务都是遗留系统服务。此类服务无法提供TCC模式中的三个接口,但可以使用Saga模式的分布式事务的每一个执行操作或步骤都是一个Ti,比如T1用于扣除库存,T2用于创建订单,T3用于支付服务.那么每个Ti对应一个补偿动作Ci,比如回复库存C1,订单回滚C2,支付回滚C3优点一次性提交本地交易,无锁,高性能参与者可以异步执行,高吞吐补偿服务容易实现,因为更新操作的逆向操作更容易理解。缺点是不保证隔离(可以看其他事务)。Saga的运行方式更像是发邮件。发送的电子邮件是正确的,收件人以正常方式解释它们。如果邮件发错了,再发一封邮件告诉收件人,请忽略之前的邮件。但有时这种操作是不可逆的。比如在分布式事务中,先给用户A充值,然后给用户B扣除余额,如果给用户A充值成功,用户A在交易提交前消耗掉余额。如果事务被回滚,则没有办法补偿。对策业务流程设计遵循“宁长补短”的原则。长支付意味着客户的钱少了,机构的钱多了。凭借机构的信誉,客户可以退还。否则就是短款,少了钱可能收不回来,所以在业务流程设计中,一定要先扣款;有些业务场景可以让业务最终成功,如果回滚无法回滚,可以继续重试完成后续流程,达到最终一致性的目的两种恢复策略正向恢复:针对失败的事务执行,他们将尝试重试交易。这里有一个假设,即每个子交易最终都会成功。该方法适用于必须成功的场景反向恢复:当一个事务执行失败时,补偿所有已完成的事务,是一种“一次回溯到底”的方法。两种模式的排列都是分散模式。参与者通过消息机制进行通信,通过监听器监听其他参与者发送的消息,从而进行后续的逻辑处理。优点很简单:每个子事务运行时只发布事件消息,其他子事务被监听和处理。松耦合:参与者(服务)之间通过订阅事件进行通信,组合起来会更加灵活。缺点理解困难存在服务循环依赖。Control定义一个控制类,告诉参与者(服务)应该执行什么操作(子事务)。Saga控制类通过命令和异步回复与参与者进行交互。优点避免循环依赖,降低复杂度:所有事务都交给controller,方便测试,容易扩展缺点依赖controller:过多的逻辑集中在controller中增加管理难度的风险:额外的管控10.2PC和3PC总结是强一致性事务,但仍然存在数据不一致、阻塞等风险,只能在数据库层面使用。TCC是一种补偿性的事务思想,适用范围更广,在业务层面实现。因此,它对业务的侵入性更大。每个操作都需要实现相应的三个方法。Saga是长事务的解决方案。它比TCC简单,但不能保证本地消息、事务消息和尽力而为通知的隔离。都是最终一致的事务,所以适合一些对时间不敏感的业务。
