电影售票系统开发流程及其bug修复日志--高可用(2)

分布式事务

首先,事务是用来保证一组数据操作的完整性和一致性。事务的四种特性,Atomicity原子性,consistency一致性,isolation隔离性,durability持久性。
分布式事务大体可以分成两部分,首先是事务,以前的分布式是一个单体性的事务,其次就是分布式,分布式事务就是将多个节点的事务看成是一个整体。现在有十个节点,每台机器部署了不同的应用,有订单支付影片等等都部署在不同机器,如果在同一个事务里,处理很简单,但是如果是在不同的事务,不同机器上,其他的事务怎么知道其他事务发生失败了,失败了又怎么处理。分布式事务一般由事务参与者,资源服务器,事务管理器组成。事务参与者类比于机器和服务,资源服务器就是用来控制比如库存数量,金额等等,最后是事务管理器,是用来辅助,比如刚刚的例子,一个事务出事了,其他的事务怎么知道,那么这个事务管理就会通知其他事务。最常见的分布式事务就是支付,下订单等。


分布式实现一般有两种,两段式事务和三段式事务,基于XA的分布式事务,基于消息的最终一致性方案,这里的信息一般是指信息队列或者是Redis一致性缓存,还有TCC编程式补偿性事务。

电影售票系统开发流程及其bug修复日志--高可用(2)_第1张图片

两段式事务和三段式事务

TC就是事务管理器,先准备好数据交流,然后双方开始提交,提交完成后告诉事务管理器,现在有两个,如果只有一个,那么久提交失败,回退即可。但是这种两段式还是有点问题的,都是在事务管理器要求你干什么就干什么,比如准备就绪了,事务管理器要你提交,结果有一台机器出问题,你怎么知道这个问题是在提交前还是提交后出现的,提交后出现的那就不用回滚了,提交前的那就要回滚。基于上述缺点,出现了三段式事务,但是都是基于两段式,只不过把第一段分成了两部分,第三段和两段式的第二段一样。三段式的第一阶段是canCommit阶段,事务管理器会给所有事务参与者发送canCommit,各个事务管理者根据自己的状态查看能否提交,如果可以则回执OK,否者返回fail,并不开启本地事务并执行。如果所有的都正常,则进入第二阶段,否则停止;第二阶段即是preCommit,事务协调器向所有参与者发起准备事务请求,参与者接受到后,开启本地事务并执行,但是不提交。第三阶段则是提交了。

基于XA的分布式事务
电影售票系统开发流程及其bug修复日志--高可用(2)_第2张图片

本质上讲还是一个两段式的提交。这个流程和前面的二三段其实是差不多的,首先询问准备好没有,准备好回个OK,然后提交执行。流程差不多,但是调用方式出现了变化,但是不常见,应用场景多,MySQL,DB2这些关系型数据库绝大多数都是基于XA来的。

基于消息一致性方案的分布式事务

电影售票系统开发流程及其bug修复日志--高可用(2)_第3张图片

这里和前面介绍的几种方式有所不同,参与者有两个A系统和消息中间件两个,首先系统A发送预备消息,中间件保存预备消息后返回说我已经收到了。接着执行本地事务,执行后把执行结果告诉消息中间件,不一定是成功的,可能成功也可能失败,消息中间件保存消息回调。可能会觉得回调和保存消息很多余,我看到这个图也是这么想的,因为执行事务无非就是成功和失败,为什么要回调保存?但是别忘了,分布式事务是多个事务之间的关系,我这里只是一个事务,将多个事务结合在一起:
电影售票系统开发流程及其bug修复日志--高可用(2)_第4张图片

如果有一个B系统,那么当A系统执行完成了,消息中间件通知了B:系统A执行完成了,然后B再执行。 在整个售票系统中有一个支付系统,钱到账了修改订单状态,但是如果钱到账了修改订单状态失败了怎么办?这个时候就可以使用消息一致性了,可以在支付宝下订单支付的时候暂停线程,启动另外一个线程进行修改订单操作。修改成功了才启用支付宝线程。这种方案是强一致性方案,同一个时刻成功一定成功,失败一起失败,不会存在其他情况,但是缺点也很明显,会存在等待时期,会使得支付宝线程等待,这样会影响性能。

TCC补偿性事务

电影售票系统开发流程及其bug修复日志--高可用(2)_第5张图片

主要进行的三个操作依次是Try接口,Confirm接口,cancel接口,confirm接口和cancel接口只能使用一个,事务要么成功要么失败。 首先启动事务协调器,告诉事务协调器要开始工作了,接着调用不同的服务,尝试进行操作,比如扣减库存和创建订单,结果A成功了,B失败了,那么业务就会调用cancel接口,成功了调用从confirm接口。try,confirm,cancel接口都是在服务里面实现,业务只是去调用这些接口,关心返回结果,根据返回结果确定是调用confirm还是cancel接口。cancel接口把try做过的东西全部取消,confirm确认提交,所以也称为是补偿式。
基于消息一致性的事务是一种强一致性的事务,很大程度上会造成资源的浪费,尤其是对于时间的浪费,上面的例子是两个事务,如果发展到多个事务,等待的时间就会更多了。但是他的优点也很明显,就是强一致性,缺点也是强一致性。在实际工程中经常会有对接京东支付,阿里支付等等的场景,假设使用TCC,那么问题来了,钱打进去是回不来的,想要调用cancel接口那只能自己掏腰包,而消息一致性就没有这种问题。TCC补偿性事务是柔性事务,在try阶段要对资源做预留,在确认和取消阶段释放资源,confirm没有什么,cancel做反向操作。相比基于消息一致性来说TCC的时效性更强。

主流的分布式框架

全局事务服务,GTS
蚂蚁金服分布式事务,DTX
开源TCC框架,TCC-Transaction
开源TCC框架,ByteTCC
这里使用TCC-Transaction开源框架。

电影售票系统开发流程及其bug修复日志--高可用(2)_第6张图片

api就是接口,core为核心包,类似于guns-core的核心,server是事务监控工具,有多少事务,事务状态,spring即是spring的支持,然后dubbo的支持,unit即为测试,tutorial教程。简要测试一下,打开简要教程,dbscripts里面执行SQL语句,会生成四个数据库:

第一个tcc的库是必须要建立的,只要使用就需要建立;下面的cap,ord,red分布模拟了业务场景,cap为资金账户,ord订单,red红包。tutorial里面有两个例子,一个是HTTP的例子,一个就是整合了dubbo的例子,HTTP的例子没有什么问题,很简单。看看dubbo的例子,首先先要部署Tomcat:
电影售票系统开发流程及其bug修复日志--高可用(2)_第7张图片

order模块的前缀/即可。打开web.xml,发现三个模块的web.xml都没有报错,是由于执行顺序的问题,错误提示 {The content of element type "web-app" must match "(icon?,display-name?,description?,distributable?,context-param ,filter,filter-mapping ,listener,servlet ,servlet-mapping,session-config?,mime-mapping ,welcome-file-list?,error-page,taglib ,resource-env-ref,resource-ref ,security-constraint,login-config?,security-role ,env-entry,ejb-ref ,ejb-local-ref)".- No grammar constraints (DTD or XML schema) detected for the document },listener要再filter-mappering和servlet之间,调整位置就好了,启动跑起来环境就搭建好了。现在就是要按照案例里面的代码把自己的项目改造一下。首先查看一下工程结构:
电影售票系统开发流程及其bug修复日志--高可用(2)_第8张图片

api和之前业务里面的api接口没有什么区别,注意有一个接口:
电影售票系统开发流程及其bug修复日志--高可用(2)_第9张图片

带有compensable标签,即是需要进行事务处理的接口,RedPacketAccountServiceImpl这个接口实现是查询红包信息而已,不需要事务支持。

当前注解的方法就是try方法,就是业务方法,注解提到的confirmMethod,cancelMethod就是TCC,最后一个参数是事务上下文支持,这里使用的是隐式上下文的支持,可能这里需要用到隐式参数传递,接下来下面就要实现两个confirm和cancel两个方法,而且必须在同一个类里,因为注解绝大多数是要通过放射和AOP来读取,如果不在同一个类里面,是没有办法找到的,类是通过包名加上类名找到的,只返回一个字符串就能找到是不可能的,所以只有放在同一个类里面才能找到
电影售票系统开发流程及其bug修复日志--高可用(2)_第10张图片

record也就是try业务,注意catch里面不是捕获所有的异常,业务TCC是根据异常的有无来判断业务执行成功或者失败,有异常才会回滚,对于业务返回的结果不关心。这里的订单多出两种状态,draft草稿和cancel取消,draft即是try完但是没有confirm的订单,confirm完成就是真正支付完成的订单了。

注意在cancel和confirm里面都需要判断订单是空而且订单状态为draft草稿状态。 但是这里涉及到一个服务幂等性的问题,即是一个服务重复多次执行和一次执行的结果相同,幂等性还不是理解的很好,做完这个服务再去看看。所以TCC的分布式事务需要注意两个部分, 1、分布式事务里,不要轻易在业务层捕获所有异常,2、使用TCC-Transaction时,confirm和cancel的幂等性需要自己代码支持。然后部署Tomcat,运行即可,注意TCC-trancation-order这个模块,在部署artificial的时候路径一个斜杠就好了。
测试完成之后就可以仿造加到这个项目上了。首先是打包,idea里面maven的package功能打包:
电影售票系统开发流程及其bug修复日志--高可用(2)_第11张图片

控制台用mvn install进去,当然了,最简单的还是直接接idea里maven install进去就好了。 (2020.1.29.凌晨1:20)

部署环境

部署环境有点麻烦,比springboot麻烦多了,再加上文档东写一点西写一点的,调试的头都大了。

你可能感兴趣的:(电影售票系统开发流程及其bug修复日志--高可用(2))