euphoria代码demo是


????设计实现一个 TCC 分布式事務框架的简单 Demo实现事务管理器,不需要实现全局事务的持久化和恢复、高可用等

????需要MySQL数据库保存全局事务信息,相关TCC步骤都會打印在控制台上

  • 2.运行当前工程的:TccDemoApplication启动以后自动创建数据库的表
  • 1.初始化:想事务管理器注册新事务,生成全局事务唯一ID
  • 2.try阶段执行:try相關的代码执行期间注册相应的调用记录,发送try执行结果到事务管理器执行成功由事务管理器执行confirm或者cancel步骤
  • 3.confirm阶段:事务管理器收到try执行荿功信息,根据事务ID进入事务confirm阶段执行,confirm失败进入cancel成功则结束
  • 4.cancel阶段:事务管理器收到try执行失败或者confirm执行失败,根据事务ID进入cancel阶段执荇后结束,如果失败了打印日志或者告警,让人工参与处理

????TCC分布式事务主要的三个阶段:

  • 1.Try:主要是对业务系统做检测及资源预留
  • 3.Cancel:取消执行业务操作

????下面以一个例子来说明三个阶段需要做的事:比如现在有两个数据库一个用户账户数据库、一个商品库存数据库,现在提供一个买货的接口当买卖成功时,扣除用户账户和商品库存大致伪代码如下:

????在上面这个操作做,两个函數的操作必须同时成功不然就会出现数据不一致问题,也就是需要保证事务原子性

????因为设定的场景是数据在两个不同的数据庫,所有没有办法利用单个数据库的事务机制它是跨数据库的,所以需要分布式事务的机制

????下面简单模拟下,在不使用TCC事务管理器按照TCC的思想,在代码中如何保证事务原子性

????使用上面的场景代码大致如下:

????上面就是一个TCC事务大致代码,可鉯看到:之前的每个函数操作都需要分为三个子函数try、confirm、cancel。将其细化在代码中判断执行,保证其事务原子性

????上面是两个服務,用户账户和商品存储操作看着写起来不是太多,但如果是多个服务呢try阶段就会多很多的if,还有相应的cancel的动态增加confirm也是,大致如丅:

????可以看出代码相似性很多工程中相似的需要分布式调用的有很多,这样的话大量这样的类似代码就会充斥在工程中,为叻偷懒引入TCC事务管理器就能简化很多

????为了偷懒,用事务管理器那偷的是哪部分懒呢?在之前的代码中try阶段还是交给本地程序去做,而confirm和cancel委托给了事务管理器下面看下Seata和Hmily的TCC伪代码:

????调试参考了Seata和Hmily的TCC,理出了大概的步骤其中的细节方面有很多很多的東西,暂时忽略主要看大体的实现

????这里进行大量的简化,使用连个注解即可能大体完成TCC整个流程,下面说一下整个TCC Demo的运行流程:

  • 1.初始化:想事务管理器注册新事务生成全局事务唯一ID
  • 2.try阶段执行:try相关的代码执行,期间注册相应的调用记录发送try执行结果到事务管理器,执行成功由事务管理器执行confirm或者cancel步骤
  • 3.confirm阶段:事务管理器收到try执行成功信息根据事务ID,进入事务confirm阶段执行confirm失败进入cancel,成功则结束
  • 4.cancel阶段:事务管理器收到try执行失败或者confirm执行失败根据事务ID,进入cancel阶段执行后结束如果失败了,打印日志或者告警让人工参与处理

????此步骤主要是,注册生成新的全局事务获取新事务的唯一标识ID。

????@TCCGlobalTransaction,这个注解就是用于标识一个事务的开始注册新的事务,将新事务的ID放入当前的threadLocal中后面的函数执行也能获取到当前的事务ID,进行自己的操作

????在其上加了 @TCCAction 注解用于注册改事务的函数調用记录:因为事务的数量是不确定的,当加这个注解的时候调用进行拦截后,会根据从threadLocal中获取的事务ID想事务管理器注册改事务的子倳务的confirm和cancel方法,用于后面事务管理能根据事务ID推动相关confirm和cancel的执行

????当上面的buy()函数执行完成以后,并成功以后发送消息给事務管理器,事务管理器就通过事务ID来推动接下来confirm阶段的执行

????当buy函数执行失败,或者confirm执行失败后根据当前的事务ID,事务管理器嶊动进入cancel阶段的执行

????代码实现部分只列出关键代码了代码还是稍微有点多的,代码实现的逻辑线如下:

  • 2.在事务函数执行的过程Φ对 @TCCAction 进行拦截:将分支事务调用信息注册到全局事务管理数据库中
  • 3.当 try 阶段执行成功或者失败的时候,向全局事务管理器发送消息
  • 4.全局事務管理器说道 try 节点的执行结束触发点发送信息推动各个分支事务的 confirm 或者 cancel 阶段的执行

????示例的全局事务使用如下:

????对注解進行拦截,生成全局事务ID放入threadLocal中,后面的函数执行就能拿到这个ID大致代码如下:


 
 
 

2.在事务函数执行的过程中,对 @TCCAction 进行拦截:将分支事务調用信息注册到全局事务管理数据库中

????注解的定义大致如下:

????使用示例大致如下:

????在分支事务执行 try(prepare函数)需要进行拦截,将其调用信息注册到全局事务管理中大致代码如下:

3.当 try 阶段执行成功或者失败的时候,向全局事务管理器发送消息

????在 @TccTransaction 中会调用整个函数的执行其过程就会触发各个分支事务 @TCCAction的执行,也就是 try 阶段的执行当 try 执行失败或者成功后,全局事务管理 推动進入 confirm 或者 cancel 阶段大致代码如下:


 
 
 
 
 
 
 
 
 
 

4.全局事务管理器说道 try 节点的执行结束触发点,发送信息推动各个分支事务的 confirm 或者 cancel 阶段的执行

????分支倳务管理器(TM)收到了消息就根据 xid 捞出所有的分支事务,根据状态判断执行 confirm 或者 cancel

????只需要处理注册上来的分支事务即可,try 执行唍的必然注册上来了后面执行 confirm即可。try 没有执行的肯定是前面的分支事务出错了,只要恢复前面的数据即可

????大致代码如下:

????到此就实现了一个非常简陋的 TCC Demo了。其中 TC 和 TM 的角色不是特别清晰因为他们基本嵌入到一个应用里面去了,但还是体现了大致的思蕗当然,TC也完全是可以分离的像Seata就是一个独立的Server。

????TC 和 TM 的通信方法也是可以用其他的这里为了方便使用的HTTP,也可以使用 RPC之类嘚

????完整的工程如下:

我要回帖

更多关于 看demo 的文章

 

随机推荐