micro-service(3):分布式事务和接口幂等性

分布式服务需要满足CAP原则,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),但三者不可得兼;一般都会优先保证可用性和分区容错性,并且保证最终一致性。BASE理论是对CAP原则的补充,Basically Available,Soft state,Eventually Consistent,也就是当CAP三者不能兼得的时候,可以做到最终一致性。

大型应用一般需要做业务分拆以便于提升业务的可维护性和扩展性,但由于业务分布于多个系统中,数据自然也分布于多个DB中,数据库事务则不再能满足业务需求。相比较于数据库事务,分布式事务需要考虑更多的可变因素,比如某一台server没有响应或者响应超时,网络延迟等,因此一般会在分布式事务中引入一个中间协调者,用于协调多个事务参与者之间的状态。
一般分布式事务处理模式包括:2阶段提交、3阶段提交、TCC(Try-Confirm-Cancel)、可靠消息(消息队列、数据库表)、SAGAS长事务、补偿性事务。具体采用哪一种分布式事务处理模式,需要根据自己业务场景来选择合适的机制。

#1 异步消息(MQ):

异步方案用于保证最终事务一致性(Eventual Transaction Consistency),流程是MP在处理完业务之后发送一个消息到MQ里,MC从MQ中获取消息并进行处理,处理完毕之后向MP发送确认消息,为了保证消息机制的可靠性MP和MC需要保证在各自系统内部的动作都在一个事务里。优点是流程简单,MP能有很快的响应速度;缺点是没有回滚机制,因此MP和MC的状态有可能不一致;

#2 两阶段提交(2PC):

两阶段提交用于保证最终一致性,流程中需要有一个协调者,在pre-commit阶段协调者触发资源锁定动作,commit或者rollback阶段协调者进行实际的资源消费动作或者释放动作;由于时候多阶段提交,所以每一次交互都可能出现异常,因此需要引入重试机制或者MQ机制。优点是可以将极大降低状态不一致发生的可能;缺点是业务操作时同步阻塞,响应速度受影响,并且受单点问题影响。
2PC最大的问题在于当参与者比较多的时候,如果第一阶段任意有一个参与者没有及时响应的话所有参与者的资源都会被锁定,所以在此基础上第一阶段分成两个小的阶段,先发送一个询问canCommit的消息,当所有参与方都响应了才进入preCommit进行资源锁定,等所有的参与方都preCommit确定之后,进入doCommit阶段,同时所有的操作都会加入等待超时设置以保证数据一致性,这样的设计就是3阶段提交(3PC)。

#3 异步事务消息(RMQ):

异步事务消息用于保证最终一致性,流程更像是结合了异步消息和2阶段提交的混合体,可以解决MP的发送给MQ的消息如果没有得到处理或者处理失败的场景,RMQ加强了对MQ的消息状态管理和重试机制的实现;MP先发送一个pre-commit的消息给MQ,然后执行本地的事务,执行成功后给MQ一个确认消息,MQ收到消息后将消息状态设置成ready,也就是MC可以消费。

#4 补偿事务(CT)或TCC(Try-Confirm-Cancel):

针对每一个操作,都注册一个与之对应的补偿操作,从而组成一个操作链和补偿操作链;一旦操作链上某一步出错后,就会按照补偿操作链相反的顺序进行执行;优点在于不用提前锁定资源,流程比较简单;缺点是补偿操作的界定范围不明确容易造成状态不一致。

分布式系统中接口的幂等性(idempotent)

分布式系统中存在这样的情况,由于网络延迟,请求具有超时重试功能,MQ发送消息和RPC调用等,某个动作可能被执行多次,但业务需求上不能接受接口方法被执行一次与执行多次的结果状态不一致,比如接口boolean withdraw(UUID account_id, Long amount)用于对指定账户扣款,如果执行多次就会多次扣款,这样的结果是不能接受的,因此需要保证接口的幂等性。幂等性指的是对于一个接口而言如果参数相同,在特定业务场景下调用一次跟调用多次的结果状态都是相同的,因此上述接口如果遵从幂等性设计的话,则不管调用几次,用户账户的钱都只会被扣除一次。有多种幂等性的接口设计策略,如one-time-use token,全局唯一ID,多版本控制,状态机控制等,实际需要根据具体的业务进行设计。

幂等性设计的基本原则是给业务请求分配一个唯一的ID,业务单元在处理业务请求之前需要判断该业务请求是否被处理过,比如业务请求到达之后先判断缓存系统中是否有ID的记录,如果没有则表示第一次请求,则正常处理业务消息并将ID存入缓存系统;如果有记录则表示该业务请求已经被处理过,则忽略当前的业务请求;业务请求ID可以有多种形式,对于本地事务而言DB的primary key可以保证唯一性,对于分布式事务而言需要根据业务进行设计。

接口boolean withdraw(UUID orderId, UUID account_id, Long amount, OrderStatus status, String token)相比之前的接口多了三个参数,token是事先从一个共享service中获取,标识一次扣款操作,共享service会将这个token存储于自身的DB中并保存状态,orderId表示业务唯一性的ID,status表示针对orderId的状态流转,因此只要对于orderId操作过一次扣款操作之后,token标记的状态就会更新(或者status就会更新成STATUS_PAID),这样不管之后的有多少次操作都不会再次执行扣款的动作。

原文地址:https://www.cnblogs.com/leo-chen-2014/p/9532287.html

时间: 2024-10-08 11:07:38

micro-service(3):分布式事务和接口幂等性的相关文章

链接服务器的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务 外加SQL事务死锁问题

”这SQL作业一直每天都运行好好的,咋突然就不生效了?” 碰到这种突发问题,我心里是淡定的,事情不可能莫名发生的,因为是SQL作业问题,首先需要查看作业历史记录 果然一个大大的X明显的不要不要的,继续看错误内容: 已以用户 NT AUTHORITY\NETWORK SERVICE 的身份执行. 事务(进程 ID 51)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品.请重新运行该事务. [SQLSTATE 40001] (错误 1205).  该步骤失败. 死锁?,好好的

没有活动事务 链接服务器的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

在windows2003下执行分布式事务的时候出现如下情况. 一. 问题现象在执行分布式事务时,在sql server 2005下收到如下错误: 链接服务器"xxxxxxx"的 OLE DB 访问接口 "SQLNCLI" 返回了消息 "没有活动事务.". 消息 7391,级别 16,状态 2,过程 xxxxx,第 16 行 无法执行该操作,因为链接服务器 "xxxxx" 的 OLE DB 访问接口 "SQLNCLI&

MSDTC问题集:链接服务器的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

尊重原著作:本文转载自http://sfwxw456.blog.163.com/blog/static/631359742009321112120248/ 一. 问题现象在执行分布式事务时,在sql server 2005下收到如下错误: 链接服务器"xxxxxxx"的 OLE DB 访问接口 "SQLNCLI" 返回了消息 "没有活动事务.". 消息 7391,级别 16,状态 2,过程 xxxxx,第 16 行 无法执行该操作,因为链接服务器

无法执行该操作,因为链接服务器 "xxxxx" 的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

在存储过程中使用事务,并且使用链接服务器时,报类似下面的错误 链接服务器"****"的 OLE DB 访问接口 "SQLNCLI10" 返回了消息 "没有活动事务.".消息 7391,级别 16,状态 2,过程 proc_SyncDiliveryData,第 20 行无法执行该操作,因为链接服务器 "*****r" 的 OLE DB 访问接口 "SQLNCLI10" 无法启动分布式事务. 度娘了很久,找到了

因为链接服务器 "IP" 的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

前言:A服务器和B服务器做好链接后,可以查询,但是用到Distributed Transaction就报错: 未处理的"System.Exception"类型的异常出现在 mes.exe 中. 其他信息: System.Data.SqlClient.SqlException: 服务器 'YICHANGMES' 上的 MSDTC 不可用.无法执行该操作,因为链接服务器 "" 的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务 根据网

无法执行该操作,因为链接服务器 "XXX" 的 OLE DB 访问接口 "SQLNCLI10" 无法启动分布式事务。

在存储过程中使用事务,并且使用链接服务器时,报以下错误:   无法执行该操作,因为链接服务器 "XXX" 的 OLE DB 访问接口 "SQLNCLI10" 无法启动分布式事务. 链接服务器"XXX"的 OLE DB 访问接口 "SQLNCLI10" 返回了消息 "没有活动事务. 解决方法: 1.修改host设置,在C:\Windows\System32\drivers\etc下,在两台服务器分别添加对方计算机的IP

分布式接口幂等性

https://www.cnblogs.com/huaixiaonian/p/9577567.html 最近跟朋友聊起这个话题,想深入了解下,于是学习总结,记录下来,此文章参考以下博客综合而来表示感谢: http://blog.brucefeng.info/post/api-idempotent http://825635381.iteye.com/blog/2276077 https://www.cnblogs.com/leechenxiang/p/6626629.html 1. 接口调用存在

分布式事务基于消息中间件实现

环境需求:假如佳先森有5个女朋友(有点复杂),每天晚上佳先森都有给他的女朋友打电话说晚安,那么每给一个女朋友打电话,其他女朋友都要进入等待状态.一个一个打下去...等打到最后一个已经是凌晨了,对方都睡了.那么有什么办法可以解决呢?此时佳先森可以利用微信公众号将自己甜言蜜语放进公众号中,让他女朋友订阅公众号,则这些女朋友不用依次等待又可收到消息.此原理就是消息队列. 一.什么是中间件 非底层操作系统软件,非业务应用软件,不是直接给最终用户使用,不能直接给客户带来价值的软件统称为中间件. 二.什么是

Apache RocketMQ 正式开源分布式事务消息

近日,Apache RocketMQ 社区正式发布4.3版本.此次发布不仅包括提升性能,减少内存使用等原有特性增强,还修复了部分社区提出的若干问题,更重要的是该版本开源了社区最为关心的分布式事务消息,而且实现了对外部组件的零依赖.接下来,本文将详细探秘RocketMQ事务消息的设计原理以及实现机制. 一.需求缘起 在微服务架构中,随着服务的逐步拆分,数据库私有已经成为共识,这也导致所面临的分布式事务问题成为微服务落地过程中一个非常难以逾越的障碍,但是目前尚没有一个完整通用的解决方案. 其实不仅仅