Hmily 源码解析(二)—— Hmily事务工作流程「建议收藏」

Hmily 源码解析(二)—— Hmily事务工作流程「建议收藏」Hmily源码解析(二)前言这一篇不想谈论Hmily源码的技术实现,而是想在过了一遍hmily的实现后把hmily的工作思路单独地整理出来再进行一次总结。看看能不能进一步有所得。以hmily-demo-springcloud为例,它的实现思路如下。Hmily事务工作流程首先它是基于切面编程来实现分布式事务的操作,及通过日志记录TCC事务的信息以保证最终一致性。前…

大家好,又见面了,我是你们的朋友全栈君。


前言

  • 这一篇不想谈论Hmily源码的技术实现,而是想在过了一遍hmily的实现后把hmily的工作思路单独地整理出来再进行一次总结。看看能不能进一步有所得。

  • 以hmily-demo-springcloud为例,它的实现思路如下。


Hmily事务工作流程

  1. 首先它是基于切面编程来实现分布式事务的操作,及通过日志记录TCC事务的信息以保证最终一致性。
  2. 前端发起的一个请求,第一次进入一个@Hmily注解的函数的时候,就进入Hmily的事务管理了。
  3. 这时会进入切面方法,生成一个日志实例(HmilyTransaction实例)。日志实例里面存储了所有后续需要操作的信息,比如流转状态,执行函数信息等等,并在后续的操作中会根据需要加入新的信息。
  4. 日志实例 有一个执行状态,一开始时是PRE_TRY(开始执行try),并会通过一个并发队列异步存储到数据库中。顺便说一句,每个微服务都有一个日志表,存储着对应的日志。
  5. 关于异步存储要多说一句,hmily在设计的时候把许多操作,尤其是对日志表的删改查操作都改用异步操作的方式,这也是hmily如此高效的一个原因,值得重点分析。
  6. 刚才说到日志实例被异步存储到数据库的日志表中了,而另一边就开始执行我们的业务函数。
  7. 如果函数内部再调用的函数仍有@Hmily注解,这时候切面里面不做其他任何操作。
  8. 如果调用的函数有@Hmily注解且是RPC函数,也就是调用其他微服务的代理接口,这时候会把事务id(transId 是事务唯一的,一个分布式事务id只有一个,且被用于日志主键),及当前的角色状态一起作为请求头的参数。
  9. 被调用的微服务接收到请求后,如果执行到带有@Hmily的函数,会根据传递过来的transId 的事务信息生成又一个事务日志信息,状态为PRE_TRY(开始执行try),并异步存储到数据库中对应该微服务的日志表中。
  10. 接着继续执行该微服务的主体方法
  11. 如果该微服务又调用了其它微服务,则同第7步到第12步。
  12. 如果执行成功,修改 事务日志的流转状态为TRYING(TRY阶段完成),如果失败了则删除日志抛出异常。
  13. 现在回到第一个微服务,如果调用成功,会把该rpc接口信息存储到日志信息里面
  14. 如果还有调用其他微服务,则同第7步到13步。
  15. 如果所有的执行都没问题,这时候会把日志的状态改为TRYING(TRY阶段完成),然后发起异步任务执行confirm操作。
  16. confirm操作里会把状态改为CONFIRMING(“confirm阶段”),并异步存储到数据库中,然后通过反射存储在日志里面的confirmMethod方法,及调用rpc接口,将执行confirm的命令发送给对应的微服务。
  17. 其它微服务接收到confirm消息后,会根据该微服务的事务日志中存储的confirmMethod集合,一一执行,或再把该命令发送给被调用的下一层微服务,重复17步骤。
  18. 如果各个微服务在执行confirmMethod时,有失败的案例,会将失败的confirmMethod重新存储到对应的事务日志中,然后隔一定时间通过定时再次执行confirmMethod。直到一一成功或超过重试次数发出信息给维护人员处理。confirmMethod失败后的定时执行的这一步各个微服务已经是各自为政了,不用再自上而下的从第一个微服务发起任务。
  19. cancel方法同16步到18步。它的触发条件是,只要在try阶段里有哪个try出问题了,异常会层层抛出到最上层,后面的try都不执行。而前面执行过的try信息或调用过的rpc接口信息都会存储在事务日志中间。后面只要同confirm阶段一样,根据这些信息执行cancelMethod方法或对RPC接口发起cancel请求。

补充说明

  • RPC上面的Hmily注解的作用只是用于连接前后两个微服务的,使它们处于同一个分布式事务之下。

  • 各个微服务内部的@Hmily才是真正用于处理分布式事务的(执行try,confirm,canel,维护事务日志等)。
    在这里插入图片描述

  • 我觉得第12步有些问题。如果之前又调用了其它微服务,且也有事务,而且有事务是成功的,那在这边因为自己执行失败了一刀切的把日志信息删掉了。而被调用的微服务的事务再执行TRY后就无法再被执行了,因为中间断代了,无法接收到第一个发起者发下来的confirm命令或cancel命令,从而不知道该执行什么,最终导致数据不一致。

  • 我觉得在设计上,hmily要求分布式事务相关的业务代码要非常纯粹,如果中间有什么伴随着时间会有不同结果的操作(比如查询),可能就会由于查询结果不的不同导致破坏了最终一致性。

  • 之前有考虑过,同一个微服务内,会不会有两个@Hmily嵌套的情况。感觉有点傻,同一个微服务内部用hibernate事务管理就好了,不应该写成@Hmily嵌套,而且当前版本的@Hmily似乎也不支持这种做法,目前无法实现这种需求。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143136.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号