1,柔性事物,二阶段2PC型,补偿型,异步确保型,最大努力通知型。redis
2PC适合场景:客户帐,收费spring
异步确保型:会计性,资金订单,通知数据。sql
核心交易数据分库并分表,消费记录数据分库分表,商户交易数据分库分表。数据库
保持多个维度的数据集群可使用MQ异步同步,MQ异步也会致使数据不一致,则引入实时监控服务,实时计算2个维度集群差别,做一致性同步。缓存
2,事务型MQ,在本地逻辑处理前发送MQ,本地逻辑执行成功后,提交commit MQ消息,MQ失败则重试直到成功。也可用MQ定时补偿,单独补偿任务表出来,这样显得更为清晰。服务器
一致性重试须要解决幂等,能够采用乐观锁,version号去重,乐观锁失败证实版本上升了,失败了走查version再更新,设计较多的去重的能够单独一张表作去重服务,利用DB惟一索引特性,或采用zookeeper和redis分布式锁lock,相似多线程并发锁。微信
避免XA事务,通讯时间较长资源锁定等待久。利用异步作最终一致性方式较好,MQ如支付宝帐号扣钱以后只生成1个MQ便可,只要该消息可靠保存,依靠该消息完成最终一致性。网络
3,微信支付采用postgreSQL数据库,XS在事务管理机制会成为系统瓶颈,全局事务管理器会限制系统的扩展规模,每一个request进来后协调节点都会向全局事务管理器GTM申请必须的全局事务ID,全局快照信息,并把这些信息随着SQL自己一块儿发往DN节点执行,只有主DN才会获取gxid,备DN没有本身的gxid。微信改进后再也不从全局事务管理器GTM获取gxid和全局快照信息,每一个节点使用本身的本地xid和快照,备DN也能够提供只读服务,先对分布式列计算hash,而后用这个值对集群中的节点个数取模决定哪一个节点。多线程
4,一致性补偿服务,须要先要肯定失败的步骤和状态,肯定补偿的范围,再能提供补偿使用的业务数据和业务流水等更多要素,当客户1个预约请求到达时,补偿协调服务为请求生成1个全局惟一的业务流水号,并在调用各个工做服务的的同时完整记录完整的状态,记录调用的业务流水,记录调用bookhotel业务流水和bookTrain流水再调用服务等,补偿过程服务一样也须要重试机制,要求自己也具备幂等性,因为业务因素失败不须要重试而是数据库等记录异常手动处理,因网络缘由则须要重试,500错误的则等一段时间再重试。架构
5,dubbo分布式事务,使用异常exception抛出,A服务调用B服务,B服务调用C服务,C服务出现异常会抛给B,B异常也会抛给A,C回滚则B也回滚,B回滚则A也回滚。MQ最终一致性能够利用系统控制MQ的消息状态如预备、发送、提交、成功、失败、重试中等。TCC补偿事务则分为try confiirm cancel三个途径,try对业务检测及资源预留confirm作业务提交,cancel作业务回滚,Try节点可能存在失败则调用cancel释放资源。 最大努力通知型多用在第三方系统通信时,如调用微信支付后结果通知,如经过MQ发送http请求,设置最大通知数,不保证成功,提供结果查询接口,多系统之间同步,Dubbo之间调用也可采用最大通知反馈。
6,用户启动1个事务,transactionManager.begin(),事务管理器在当前线程初始化1个事务实例,threadLocal.set( new TransationImpl() ),用户调用jdbc/jms/dubbo请求,请求内部初始化1个XAResource实例,XAResource xsResource = new XAResourceImpl(); jdbc/jms/dubbo从当前线程获取事务,transation将当前XAResource注册到事务中,transation.enlistResource(xsResource),用户提交1个事务:transationManager.commit()。事务for循环调用全部注册的XAResource的2阶段提交,Xid xid = new XidImpl(); for(XAResource x : xaResources){ x.prepare(ID), xa.commit(xid, true); 还有些异常流程如rollback和forget等,距离TransationManager tm = newTransationManager (); JNDI并行lockup方式获取,tm.begin() 肯定事务, jdbcConn执行update sql,DB写入binlog,但不更新表,jmsMQ发送消息msg可是不执行提交,dubbo invoke调用远程服务,provider缓存请求不执行提交,全部提交后捕获异常rollback。
7,四个dubbo服务,2个失败则等4个任务全执行完毕后回调,定时任务检测4个dubbo服务数据是否一致,一致则所有置为成功,不一致则所有置为失败 。
8,发红包,推送,统计,分订单,支付,网银第三方等异步操做使用最终一致性,重试幂等等,如退款遇到故障会延时退款,保证最终会被完成,不过须要判断退款保持幂等性,若是发生退款失败则放入延时队列,稍后重试。退款操做最终必定会完成。
9,不少交易环节采用MQ来流转,业务操做上先将订单持久化到同一个事务里面,共享订单操做的持久化DB链接,在这个DB链接中将MQ持久化到同一个实例的消息库中,而后在事务提交之江消息发送到MQ server,事务回滚后消息不会发出去,订单持久化,MQ持久化到DB,事务提交MQ发出去,发送成功则删除DB中的消息表记录,若是发送失败,后台有1个任务会将消息表中发送失败的消息从新发送,达到最终一致性,或者producer是发或者补发,提供1个broker反查接口。也能够采用spring等自带的MQ事务进行延时重试等。幂等能够采用状态机,或者携带版本号,和DB中的进行对比,后台扫描制定的时间以内的DB消息表,server段据消息ID作1个去重。
10,A,前者1个嵌入客户端应用的jar负责事务,数据写入处理,后者独立系统,负责异常、事务恢复、2PC需参与者须要一直到持有资源直到整个分布式事务结束,千万级,性能不好,1个业务服务若干个从,主发起完成整个业务,从做TCC型业务操做,业务活动管理器控制业务活动一致性,登记业务活动中的操做,在活动提交时确认全部的2阶段事务的操做,业务取消时能够调用全部2阶段事务cancel操做。
B,发起支付,增长用户积分,调用dubbo支付扣款,支付状态处理,成功则提交事务,失败则回调订单积分,未知则等到支付系统回调状态。
C,用户信息变动同步至各业务系统activeMQ中,订阅方式保证单次消费。
D,非实时非强一致性的业务采用MQ,能够重试和事务消息。
E,事务提交以前插入1条消息记录,事务提交以后再一步将该消息发出去,成功则将消息记录删除,失败则保留该消息记录,会有1个服务不断扫描消息从新发送。
11,跨银行转帐,2个异地service服务,构成1个完整事务,事务补偿即链中每一个正向事务必须有1个彻底符合回滚的逆向事务,调用本地取款,成功并返回数据已持久化,而后调用异地存款,如失败则调用本地逆向服务,如本地存服务调用失败则必须重试,约定重试次数仍然失败则必须log到完整的不一致信息(也能够MQ),为了不手工写大量的代码,考虑1个通用的事务管理器,实现事务链和上下文的管理。任务1个正向和逆向均在事务管理器上注册,由事务管理器接管全部在事务补偿和回滚操做。
消息一致性调用本地取款服务,而后发送MQ,MQ消费对消息解析后调用异步存款服务,失败则重试,不得已本地取款通常不可逆。(能够存在真空期时间内事务最终一致性)。幂等性重试重复调用屡次产生的业务结果和1次调用同样,由于调用失败异常必须考虑。
12,一致性结果可能成功,失败或者不肯定,成功就能够把记录的东西清理掉,对于失败和不肯定,能够依靠定时方式把全部失败的事情从新尝试一遍,直到成功为止。系统在A扣钱成功下,把要给B通知这件事记录到数据库中,为了保证可靠性能够把通知B系统加钱和扣钱成功这2件事维护在本地1个事务里面,本地事务维护业务变化和通知消息一块儿落地(失败则一块儿回滚),而后RPC到达broker,在broker成功落地后RPC返回成功,本地消息记录能够删除,不然本地消息记录一致靠定时器任务轮询不断重发,这样就保证了消息可靠落地broker。broker一致发消息给consumer,直到consumer确认消费成功,先不理会重复消费,以来状态机作版本号去重,实现最终一致性。
13,顺带记录下spring的5中事务方式,每一个bean都有1个事务代理;全部bean共享1个事务代理;使用拦截器;使用tx标签配置的拦截器;全注解方式。
14,建立不可见订单,同时锁券,失败则发送废弃订单消息到MQ,而后回库存和回券,锁券成功则订单变为可见。支付系统回调请求会重试到MQ,交易系统会更新交易主子菜单,交付单,减库存,加销量,送券等,若是业务失败则放入重试表,做重试。其中资金做为发起方保证重试和MQ可达。
15,最终一致性,T1发送half消息,T2存储half消息,T3返回消息入库结果,T3业务操做,S1定时检查未提交的消息,S2提交回滚,S3提交更新DB/回滚删除消息。
16,XA事务:1个数据库只将其操做(可恢复)映射到全局事务中(交易中间件),由它通知协调相关数据库的提交和回滚
2PC(二阶段):参与者将本身操做成败通知协调者,再由协调者根据全部参与者反馈状况情报决定参与者是否须要提交操做仍是终止。2阶段为准备阶段和提交阶段。分为三个步骤,A协调者节点向全部参与者询问是否可执行提交,并等待全部参与者响应 B参与者节点询问发起为止全部事务操做,并将undo和redo写入日志 C各参与者节点响应协调者发起的询问,若是参与者节点事务操做实际执行成功,则返回1个赞成,参与者操做失败则返回1个终止。
17,Sagas长事务
在Sagas事务模型中,一个长事务是由一个预先定义好执行顺序的子事务集合和他们对应的补偿子事务集合组成的。典型的一个完整的交易由T一、T二、……、Tn等多个业务活动组成,每一个业务活动能够是本地操做、或者是远程操做,全部的业务活动在Sagas事务下要么所有成功,要么所有回滚,不存在中间状态。
Sagas事务模型的实现机制:
每一个业务活动都是一个原子操做;
每一个业务活动均提供正反操做;
任何一个业务活动发生错误,按照执行的反顺序,实时执行反操做,进行事务回滚;
回滚失败状况下,须要记录待冲正事务日志,经过重试策略进行重试;
冲正重试依然失败的场景,提供定时冲正服务器,对回滚失败的业务进行定时冲正;
定时冲正依然失败的业务,等待人工干预;
Sagas长事务模型支持对数据一致性要求比较高的场景比较适用,因为采用了补偿的机制,每一个原子操做都是先执行任务,避免了长时间的资源锁定,能作到实时释放资源,性能相对有保障。
Sagas长事务方式若是由业务去实现,复杂度与难度并存。在咱们实际使用过程当中,开发了一套支持Sagas事务模型的框架来支撑业务快速交付。
开发人员:业务只须要进行交易编排,每一个原子操做提供正反交易;
配置人员:能够针对异常类型设定事务回滚策略(哪些异常归入事务管理、哪些异常不归入事务管理);每一个原子操做的流水是否持久化(为了避免同性能能够支持缓存、DB、以及扩展其它持久化方式);以及冲正选项配置(重试次数、超时时间、是否实时冲正、定时冲正等);
Sagas事务框架:提供事务保障机制,负责原子操做的流水落地,原子操做的执行顺序,提供实时冲正、定时冲正、事务拦截器等基础能力;
Sagas框架的核心是IBusinessActivity、IAtomicAction。IBusinessActivity完成原子活动的enlist()、delist()、prepare()、commit()、rollback()等操做;IAtomicAction主要完成对状态上下文、正反操做执行。
限于文章篇幅,本文不对具体实现作详述;后面找时间能够详细介绍基于Sagas长事务模型具体的实现框架。Sagas长事务须要交易提供反操做,支持事务的强一致性,因为没有在整个事务周期内锁定资源,对性能影响较小,适合对数据要求比较高的场景中使用。
18,可靠事件模式(本地事件表、外地事件表)
可靠事件模式属于事件驱动架构,当某件重要事情发生时,例如更新一个业务实体,微服务会向消息代理发布一个事件。消息代理会向订阅事件的微服务推送事件,当订阅这些事件的微服务接收此事件时,就能够完成本身的业务,也可能会引起更多的事件发布。
可靠事件模式在于保证可靠事件投递和避免重复消费,靠事件投递定义为:
每一个服务原子性的业务操做和发布事件;
消息代理确保事件传递至少一次;避免重复消费要求服务实现幂等性。
基于事件模式,须要重点考虑的是事件的可靠到达,在咱们产品实际支持过程当中,一般有本地事件表、外部事件表两种模式:
一、本地事件表方法将事件和业务数据保存在同一个数据库中,使用一个额外的“事件恢复”服务来恢复事件,由本地事务保证更新业务和发布事件的原子性。考虑到事件恢复可能会有必定的延时,服务在完成本地事务后可当即向消息代理发布一个事件。
微服务在同一个本地事务中记录业务数据和事件;
微服务实时发布一个事件当即通知关联的业务服务,若是事件发布成功当即删除记录的事件;
事件恢复服务定时从事件表中恢复未发布成功的事件,从新发布,从新发布成功才删除记录的事件;
其中第2条的操做主要是为了增长发布事件的实时性,由第三条保证事件必定被发布。本地事件表方式业务系统和事件系统耦合比较紧密,额外的事件数据库操做也会给数据库带来额外的压力,可能成为瓶颈。
二、外部事件表方法将事件持久化到外部的事件系统,事件系统需提供实时事件服务以接受微服务发布事件,同时事件系统还须要提供事件恢复服务来确认和恢复事件。
业务服务在事务提交前,经过实时事件服务向事件系统请求发送事件,事件系统只记录事件并不真正发送;
业务服务在提交后,经过实时事件服务向事件系统确认发送,事件获得确认后,事件系统才真正发布事件到消息代理;
业务服务在业务回滚时,经过实时事件向事件系统取消事件;
若是业务服务在发送确认或取消以前中止服务了怎么办呢?事件系统的事件恢复服务会按期找到未确认发送的事件向业务服务查询状态,根据业务服务返回的状态决定事件是要发布仍是取消;
该方式将业务系统和事件系统独立解耦,均可以独立伸缩。可是这种方式须要一次额外的发送操做,而且须要发布者提供额外的查询接口。
基于可靠事件的事务保障模式能够有不少的变种实现,好比对消息可靠性不高的话,能够将本地表的方式换作缓存方式。为了提升消息投递的效率,能够将屡次消息合并为投递模式。为了提供强一致性的事务保障,甚至能够将本地消息表持久化(保障发方法消息可靠落地)+远程消息表持久化(保障接收方消息可靠落地)结合的模式。
在咱们的流程产品中针对业务和流程的分布式事务解决方案就采用了屡次消息合并投递+本地缓存+远程消息表持久化的模式,接下来为你们介绍具体的使用方式。
使用场景
在实际业务项目中一般采用业务与流程分布式部署的模式,业务系统经过远程接口访问流程引擎,业务数据同流程数据存放到各自的数据库中。
在这种场景中,若是业务系统的流程操做和业务操做交叉在一块儿,当流程操做成功,而业务操做失败时,就会形成业务回滚,而流程在引擎端已经建立,致使业务系统和流程引擎状态不一致。
在业务应用中对一个事务中的流程操做采用本地缓存+批量投递+远程落地的模式(若是须要在客户端确保消息可靠性,能够将本地缓存换成本地表的方式);在流程引擎端在消息投递来以后,作了消息表落地的工做,保障可靠执行。在咱们流程产品中流程引擎对外提供的客户端提供了统一的分布式事务API,和使用传统本地事务同样进行操做,保证了透明性,简化开发人员的复杂度。分布式事务API支持两种协议模式:
HTTP + 二进制序列化的模式
WebService模式
后续咱们会增长Restful风格的接口。
可靠事件模式在互联网公司中有着较大规模的应用,该方式适合的业务场景很是普遍,并且可以作到数据的最终一致性,缺点是该模式实现难度较大,依赖数据库实现可靠性,在高并发场景下可能存在性能瓶颈,须要在公司层面搭建一套标准的可靠事件框架来支撑。
可靠事件模式(非事务消息、事务消息)
可靠事件模式的事件通知能够采用消息的模式来实现,其实现原理和本地事件表、外部事件表一致,本文就不在详述。目前经常使用的消息框架ActiveMQ、RabbitMQ、Kafka、RocketMQ能够用来做为消息投递的渠道。注意:Kafka一般不适合,由于Kafka的设计存在丢消息的场景。
目前市面上支持事务的消息产品比较少,RocketMQ虽然实现了可靠的事务模式,但并无开源出来、没有开源出来、没有开源出来,顺便说一下国内的开源有太多须要改进的空间(关键点不开源,开源后没有持续的投入)。