当前位置:首页>开发>正文

hmily原理

2024-07-28 22:59:02 互联网 未知 开发

hmily原理?

hmily原理


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


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


Hmily事务工作流程

首先它是基于切面编程来实现分布式事务的操作,及通过日志记录TCC事务的信息以保证最终一致性。

前端发起的一个请求,第一次进入一个@Hmily注解的函数的时候,就进入Hmily的事务管理了。

这时会进入切面方法,生成一个日志实例(HmilyTransaction实例)。日志实例里面存储了所有后续需要操作的信息,比如流转状态,执行函数信息等等,并在后续的操作中会根据需要加入新的信息。

日志实例 有一个执行状态,一开始时是PRE_TRY(开始执行try),并会通过一个并发队列异步存储到数据库中。顺便说一句,每个微服务都有一个日志表,存储着对应的日志。

关于异步存储要多说一句,hmily在设计的时候把许多操作,尤其是对日志表的删改查操作都改用异步操作的方式,这也是hmily如此高效的一个原因,值得重点分析。

刚才说到日志实例被异步存储到数据库的日志表中了,而另一边就开始执行我们的业务函数。

如果函数内部再调用的函数仍有@Hmily注解,这时候切面里面不做其他任何操作。

如果调用的函数有@Hmily注解且是RPC函数,也就是调用其他微服务的代理接口,这时候会把事务id(transId 是事务唯一的,一个分布式事务id只有一个,且被用于日志主键),及当前的角色状态一起作为请求头的参数。

被调用的微服务接收到请求后,如果执行到带有@Hmily的函数,会根据传递过来的transId 的事务信息生成又一个事务日志信息,状态为PRE_TRY(开始执行try),并异步存储到数据库中对应该微服务的日志表中。

接着继续执行该微服务的主体方法

如果该微服务又调用了其它微服务,则同第7步到第12步。

如果执行成功,修改 事务日志的流转状态为TRYING(TRY阶段完成),如果失败了则删除日志抛出异常。

现在回到第一个微服务,如果调用成功,会把该rpc接口信息存储到日志信息里面。

如果还有调用其他微服务,则同第7步到13步。

如果所有的执行都没问题,这时候会把日志的状态改为TRYING(TRY阶段完成),然后发起异步任务执行confirm操作。

confirm操作里会把状态改为CONFIRMING(“confirm阶段”),并异步存储到数据库中,然后通过反射存储在日志里面的confirmMethod方法,及调用rpc接口,将执行confirm的命令发送给对应的微服务。

其它微服务接收到confirm消息后,会根据该微服务的事务日志中存储的confirmMethod集合,一一执行,或再把该命令发送给被调用的下一层微服务,重复17步骤。

如果各个微服务在执行confirmMethod时,有失败的案例,会将失败的confirmMethod重新存储到对应的事务日志中,然后隔一定时间通过定时再次执行confirmMethod。直到一一成功或超过重试次数发出信息给维护人员处理。confirmMethod失败后的定时执行的这一步各个微服务已经是各自为政了,不用再自上而下的从第一个微服务发起任务。

cancel方法同16步到18步。它的触发条件是,只要在try阶段里有哪个try出问题了,异常会层层抛出到最上层,后面的try都不执行。而前面执行过的try信息或调用过的rpc接口信息都会存储在事务日志中间。后面只要同confirm阶段一样,根据这些信息执行cancelMethod方法或对RPC接口发起cancel请求

它以零侵入以及快速集成方式能够方便的被业务进行整合。


在性能上,日志存储异步(可选)以及使用异步执行的方式,不损耗业务方法方法。


之前是由我个人开发,目前由我在京东数科已经重新启动,未来将会是金融场景的分布式事务解决方案。

它的作用是,每当使用feign调用远程接口时,都会在请求头中添加上事务上下文信息

每执行一步,都会即时记录相应事务状态,比如执行confirm方法,这时候如果confim执行失败了,由于相应的事务状态没有更新,后端的定时器会不断查询失败的事务,持续调用该方法。