作者:刘月财

本文首要介绍 seata-go 中 TCC 的规划思路、反常处理以及在实战中的运用。

Seata 是一款开源的分布式业务处理计划,致力于为现代化微服务架构下的分布式业务供给高性能和简略易用的分布式业务服务。Seata 将为用户供给了 AT、TCC、SAGA 和 XA 等多种业务形式,协助用户处理不同场景下的业务问题。同时,Seata 还支撑多言语编程,而且供给了简易的 API 接口、丰厚的文档以及快速上手的 samples 示例项目,也能快速协助开发者入门并上手 Seata 的运用。

Seata-go 是 Seata 多言语生态中 golang 言语的完结计划,它致力于协助 golang 开发者也能运用 Seata 的才能来处理分布式业务场景的问题。 Seata-go 复用了 Seata TC 的才能,client 的功用和 Seata 保持一致。现在 Seata-go 现已支撑了 TCC 和 AT 形式,XA 形式正在测验中,估计会在 5 月份发版。Saga 形式正在规划和规划中,后边也会和 Seata 的 Saga 功用保持一致。

本文首要从以下几个视点,介绍 Seata-go 中的 TCC 形式的规划与运用:

  • Seata-go TCC 完结原理
  • Sata-go TCC 反常处理
  • Seata-go 的展望

Seata-go TCC完结原理

Seata-go 采用了 getty 做 TCP 网络通信,完全完结了 Seata 的通信协议。基层完结了装备中心和注册中心,也支撑了很多的第三方结构的接入,比方 dubbo、grpc、gorm 等等,现在也正在活跃和各个社区交流,以支撑更多结构的接入。Seata-go 简易的体系架构图如下:

Seata-go TCC 设计与实现

先来简略回忆下 TCC 形式的意义。TCC 是分布式业务计划的一种完结,它采用了二阶段提交协议,TCC 的全称是 Try-Confirm-Cancel,Try 是预留资源操作,Confirm 是提交操作,Cancel 是回滚操作。在 TCC 的一阶段中,先触发一切的子业务履行 Try 操作,假如一切的子业务的一阶段都履行成功,那么会触发一切子业务二阶段履行 Confirm 操作,否则二阶段履行 Cancel 操作,以此来保证各个子业务状况的一致性。

TCC 是一种侵入式的分布式业务计划,Try、Confirm 和 Cancel 三个阶段的逻辑,都需求用户自己去完结。这样做意味着更多的代码量,以及对业务很大的侵略性;而长处是则比较灵敏,能由用户随意发挥以处理更复杂的分布式业务场景的问题。

在介绍 Seata-go 的 TCC 形式之前,先来回忆下 Seata 中的三个中心人物,即 TC、TM 和 RM。TC 是业务协调者,担任维护大局业务的状况,以及触发分支业务的提交和回滚动作;TM 是业务办理器,担任子业务的编排,以及大局业务的提交和回滚动作;RM 是资源办理器,办理分支业务处理的资源,比方 MySQL 数据库的操作等。

了解了这三个中心人物,就能够大致的理解下 TCC 的业务流程,大致分为以下几个步骤:

  • TM 向 TC 发送恳求,敞开大局业务,TC 侧记载下大局业务的状况信息;
  • TM 分别向一切的 RM 发送恳求,RM 会向 TC 注册分支业务,然后履行 Try 阶段的逻辑;
  • 假如傍边某个 RM 给 TM 回来 Try 阶段履行失利,那 TM 就向 TC 发送“回滚大局业务” 的恳求。TC 收到后,就会向一切已履行 Try 的 RM 发送 Rollback 指令,触发 RM 履行 Cancel 逻辑;
  • 假如一切的 RM 都给 TM 回来 Try 阶段履行成功,那 TM 就向 TC 发送“提交大局业务” 的恳求。TC 收到后,就会向一切已履行 Try 的 RM 发送 Commit 指令,触发 RM 履行 Commit 逻辑。

至此,一个完整的分布式业务就履行完了,以下是这个过程的流程图:

Seata-go TCC 设计与实现

在 Seata-go 中,为了便利用户运用,供给了两种界说 TCC 服务办法,一种是完结 TwoPhaseInterface 接口,具体如下:

Seata-go TCC 设计与实现

另一种是经过 tag 的办法来界说 TCC 服务,这种办法会相对复杂点,可是也愈加的灵敏:

Seata-go TCC 设计与实现

第二种 tag 的计划,首要是为了满足一些特殊的场景,比方说,dubbo-go 的 server 和 client 是运用 tag 的办法来界说的,这个时分就需求运用 tag 的办法来界说 TCC 的服务。一般状况推荐运用第一种承继接口的办法来做,比较简略。

在实际运用的时分,用户只需求做以下几件事情即可:

  • 界说好自己的 TCC 服务,能够参阅上面介绍的这两种办法之一都能够;
  • 调用 TCC 的署理办法 NewTCCServiceProxy ,将 TCC 服务的封装成署理;
  • 编排好自己的子业务,传入到分布式业务的入口办法 WithGlobalTx 办法即可。

这里截图给大家看个例子,更具体的 samples 请参阅 seata-go-samples 项目,地址为:github.com/seata/seata…

Seata-go TCC 设计与实现

Seata-go TCC 反常处理

在实际运用 TCC 的时分,因为网络或是业务代码逻辑履行时间等要素,可能会出现以下的问题:

  • 幂等: 在业务的一、二阶段,因为网络推迟或是其他原因,RM 没有及时给 TC 或 TM 呼应,导致 RM 被重复触发履行一、二阶段的逻辑,这个时分,需求考虑业务的幂等;
  • 空回滚: 因为网络推迟或是其他原因,RM 在未收到 Try 恳求的状况下,却收到了 Rollback 恳求,形成空回滚的问题;
  • 悬挂: 因为网络推迟或是其他原因,RM 在未收到 Try 恳求的状况下,收到了 Rollback 恳求,处理完 Rollback 恳求后,又收到了 Try 恳求。这时大局业务已完毕,会导致业务预留的资源一直无法开释。

在 Seata-go 中,供给了两种处理计划,来协助用户处理这个问题。

第一种办法的原理和 Seata Java 的处理逻辑是相同的,都是借助 tcc_fence_log 业务状况表来做的:

Seata-go TCC 设计与实现

用户需求在自己的业务数据库中,创建这个表,RM 在提交业务 SQL 的时分,同时会在这个表里面插入一条记载,这俩 SQL 是在一个本地业务中完结的。因为这个表中,“大局业务ID+分支业务ID”是一个联合主键,导致重复履行时会失利,这样就处理了 Try 阶段的幂等问题。在 Commit 和 Cancel 阶段时,会先查询这个表中分支业务的状况,然后才进行实际的逻辑,最后再更新状况。这样也能保证 Commit 和 Cancel 阶段的幂等性。

再来看看 Seata-go 是怎么处理业务悬挂和空回滚的问题。假如一个 Rollbback 恳求过来,RM 去查询 tcc_fence_log 表,发现没有记载(因为 RM 尚未收到 Try 恳求),此时会往 tcc_fence_log 表插入一条记载,并符号状况为 suspend,然后直接退出,而不会去履行 Rollback 的逻辑,这样就避免了空回滚的问题。假如 RM 后边再收到 Try 恳求,因为 tcc_fence_log 表现已有一条记载,就会导致业务 SQL 无法提交而失利(tcc_fence_log 会出现主键冲突的问题),这样就避免了防悬挂的问题。

要完结这种办法,需求运用 Seata-go 供给的署理数据源,这些操作都会由署理数据源来完结,用户只需求敞开开关,关注自己的业务 SQL 即可,这个功用现已完结,会在后续进行发版。

第二种办法,是经过用户手动的办法来完结的。原理和上面相似,可是 tcc_fence_log 的操作逻辑需求由用户自己完结,下面的截图描述了大致的运用办法,详情能够参阅这个 samples 代码:

github.com/seata/seata…

Seata-go TCC 设计与实现

Seata-go 展望

Seata-go 社区近期与不少国内 go 言语微服务结构以及 ORM 结构背后的开发社区达到协作,比方 GORM 结构,现已集成到了 Sample 中,后续会将更多的 ORM 结构集成在 Seata-go-Samples 项目中。与 MOSN 社区的协作也在推动中,可完结真正的基于 Seata 的 Transaction Mesh。

Seata-go 的 XA 形式会在5月份进行发版,届时 Seata-go 将支撑 TCC、XA 和 AT 三种业务形式。Seata-go 后续的中心将会在 Saga 形式功用的开发上。

当前的 Saga 形式仅完结了服务编排的正向推动与反向 Rollback 才能,更进一步的服务编排则能够完结 DAG、守时使命、使命批量调度,掩盖工作流的一切流程,提升用户在 Seata 这个平台上的运用体会。现在 Seata-go 依赖于 Seata Java 的 TC,依照这个工作计划,可能需求在未来的 Seata-go 版本中完结一个功用更强壮的 TC 调度。

Seata-go 社区现在正在快速生长中,希望有更多对开源感兴趣的小伙伴,加入到咱们社区来,一起助力 Seata-go 的生长!