一个用go实现的分布式事务框架

简介: 一个用go实现的分布式事务框架

easycar是什么


easycar 是一个用go实现的支持两阶段提交协议的分布式事务框架。目前还只支持TCC,SAGA 模式,其他模式待开发。在介绍easycar 之前,先简单介绍几个角色。


Transaction Coordinator(TC)


负责全局事务的管理,所有参与分布式事务的分支都会注册到coordinator,会给每个分布式事务分配一个唯一id,当然还包括驱动全局 begin / commit /abort(我喜欢称rollback)


Transaction Manager (TM)


有些时候也叫 Transaction Client,当然不同的实现也许都会换个名字,但是职责都大差不差。一般通过TM对每个参与的RM发起一阶段的请求,如果一阶段的RM全部成功,那么TM会向TC发起commit请求,否则发起rollback。


Resource Manager(RM)


用户维度的角色,管理本地事务处理的资源。其实你可以这么理解,假设你的订单服务部分接口参与了分布式事务,无论是第一阶段TM调用接口,还是TC第二阶段调用接口,你的订单服务都会去负责本地的事务修改。

那么 easycar 上述角色有什么不同吗?有的。既然TC负责的就是全局事务的管理,那么我把职责都给了它。即由TC每个参与的RM发起一阶段的请求,然后再根据一阶段的结果,发起二阶段的请求。由TC接管整个分布式事务的生命周期。是的,我弱化了上面TM的能力。在我眼里,TM本质上就是一个客户端。客户端只需要做一些数据封装,简便化操作即可。所以即使没有客户端,其他语言的用户也可以直接通过http请求easycar服务接口。所以理论上,大部分模式下,不需要客户端也是可以直接使用easycar服务的。


支持协议和事务模式同时混用


参与分布式事务的服务往往由不同的多个部门维护,或者部分新老项目交错,可能无法保证服务的协议是一致的。另外,不同的服务所采用的事务模式具体是由:业务场景以及构造的成本来决定的。所以参与分布式事务之间所使用的事务模式不一定是统一的。在这些基础上,easycar支持协议混用(目前支持http和原生的grpc服务),支持部分事务模式混用(目前支持TCC,Saga)。


支持并发执行


假如现在有 order,account以及stock三个服务。由这三个服务组成一个分布式事务。当用户下单时,需要经过这三个服务中内部一些接口(account 扣钱,stock减库存,order 创建订单)。如果只是同步执行第一阶段,那么第一阶段总执行时间= (account+stock+order)。很多场景下,分布式事务之间并不会存在执行依赖先后的关系。所以多个子事务一阶段可以同时并发执行。流程就像这样


1668517036317.jpg


上图我们需要保证创建订单前必须先执行account扣减余额和stock扣减库存服务,才能创建订单order的服务。同时account和stock服务并不需要保证他们的执行顺序。那么我们一阶段总执行耗时可以粗略=max(account,stock)+order。因此,easycar是支持分层并发执行的。对参与的RM通过设置的权重做分层,同一层的RM可以并发调用,一层处理完毕再接下一层。在这个基础上,当某个RM发生调用错误时,那么后面一层也不会执行了,整个分布式事务需要回滚。


异常处理


分布式事务中会出现一些问题,比如

  • 空补 Cancel请求到来时,Try还没有执行,这时候这样的请求我们不能执行,理应直接返回。
  • 悬挂:Try执行时,Cancel已执行完成,不能执行,直接返回。
  • 幂等:所有操作的接口都存在这个问题。

这些问题需要用户自己去解决,框架不会自动帮你处理。在我看来,这些问题本身就是服务的必要工作,而不是通过外部服务来帮你保证换句话说,前端说它参数做了校验,难道后端就不校验接口了吗?


重试


这一块暂时还没决定最终方案。我眼中的重试有两种模式:同步和异步。同步的意思是说,当请求RM服务发生错误的时候(网络、服务本身挂了、或者服务里的中间件挂了),通过固定次数固定时间重试,这个时间通常很短,比如一秒。问题是服务挂的情况下,短时间大概率好不了,重试几乎可能是无用功。整个过程,客户端是阻塞等待的,白白耗费时间。异步重试采用指数退避算法之类的逻辑,比如第一次重试1分钟后,第二次2分钟.....,限制一个上限值,比如最多延迟一个小时还是不行的话,那只能发告警,线下处理了。这样的弊端是

  • 首先用户不能实时获取本次分布式事务结果了(正在重试中),只能等到真正执行完毕的时候通过回调的方式异步通知用户分布式事务最终结果。
  • 退避时间越长,就意味着数据不一致的时间越长。但是如果人工直接干预又存在极大的风险。比如在你人工干预的同时,正好逻辑已经开始执行了,可能会造成新的数据不一致。


状态流转图


easycar global 状态流转图


1668517064263.jpg


最后


easycar 开发不是很久,它还有好多工作需要去完成。感兴趣的可以一起加入项目地https://github.com/wuqinqiang/easycar

相关文章
|
1天前
|
运维 NoSQL Java
SpringBoot接入轻量级分布式日志框架GrayLog技术分享
在当今的软件开发环境中,日志管理扮演着至关重要的角色,尤其是在微服务架构下,分布式日志的统一收集、分析和展示成为了开发者和运维人员必须面对的问题。GrayLog作为一个轻量级的分布式日志框架,以其简洁、高效和易部署的特性,逐渐受到广大开发者的青睐。本文将详细介绍如何在SpringBoot项目中接入GrayLog,以实现日志的集中管理和分析。
15 1
|
14天前
|
数据采集 分布式计算 并行计算
Dask与Pandas:无缝迁移至分布式数据框架
【8月更文第29天】Pandas 是 Python 社区中最受欢迎的数据分析库之一,它提供了高效且易于使用的数据结构,如 DataFrame 和 Series,以及大量的数据分析功能。然而,随着数据集规模的增大,单机上的 Pandas 开始显现出性能瓶颈。这时,Dask 就成为了一个很好的解决方案,它能够利用多核 CPU 和多台机器进行分布式计算,从而有效地处理大规模数据集。
40 1
|
16天前
|
存储 NoSQL 算法
Go 分布式令牌桶限流 + 兜底保障
Go 分布式令牌桶限流 + 兜底保障
|
16天前
|
监控 Go API
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
|
3天前
|
消息中间件 NoSQL Go
PHP转Go系列 | ThinkPHP与Gin框架之Redis延时消息队列技术实践
【9月更文挑战第7天】在从 PHP 的 ThinkPHP 框架迁移到 Go 的 Gin 框架时,涉及 Redis 延时消息队列的技术实践主要包括:理解延时消息队列概念,其能在特定时间处理消息,适用于定时任务等场景;在 ThinkPHP 中使用 Redis 实现延时队列;在 Gin 中结合 Go 的 Redis 客户端库实现类似功能;Go 具有更高性能和简洁性,适合处理大量消息。迁移过程中需考虑业务需求及系统稳定性。
|
8天前
|
分布式计算 资源调度 Hadoop
在YARN集群上运行部署MapReduce分布式计算框架
主要介绍了如何在YARN集群上配置和运行MapReduce分布式计算框架,包括准备数据、运行MapReduce任务、查看任务日志,并启动HistoryServer服务以便于日志查看。
23 0
|
11天前
|
缓存 分布式计算 Java
详细解读MapReduce框架中的分布式缓存
【8月更文挑战第31天】
11 0
|
15天前
|
消息中间件 SQL 关系型数据库
go-zero微服务实战系列(十、分布式事务如何实现)
go-zero微服务实战系列(十、分布式事务如何实现)
|
16天前
|
SQL JavaScript Go
Go Web 服务框架实现详解
Go Web 服务框架实现详解
|
16天前
|
Kubernetes Go 数据库
go-zero 分布式事务最佳实践
go-zero 分布式事务最佳实践