文|赵新(花名:于雨 )
蚂蚁集团可信原生部工程师阿里开源先锋人物、阿里开源大使
负责蚂蚁可信原生技术部 DB Mesh 系统开发,以及容器和分布式事务开源工作
本文 3846 字,阅读 10 分钟
|引语|
分布式事务是微服务技术体系中非常关键的的一个技术节点,当下最流行且经过大规模生产验证的高质量分布式事务实现无疑是 Seata。Seata 社区过去四年长期专注于 Java 语言实现,在 Java 领域是事实上的分布式事务技术标准平台。
在诸如 gRPC 等微服务体系都在进行多语言建设的当下,分布式事务也应该有多种语言支持。所以在规划 2022 年 Seata Roadmap 时,其中一个非常的关键点就是 Seata 的多语言技术体系建设。在经过半年的准备特别是完成了 Seata v1.5.2 发版后,社区在今年 (2022年) 下半年的重点任务就是全力建设 Seata 的多语言实现。
PART. 1--关键技术点
Seata Java 版本经过四年建设后,已经形成了一个非常庞大的技术体系。在进行多语言建设时,想要在半年内让多语言版本 Seata 的功能与 Seata Java 完全对齐,是不可能的。社区需要综合考量当下的实际迫切需求以及未来的发展方向,先找出 Seata 多语言版本的关键技术点。
1. 事务模式
Seata 提供了 TCC、SAGA、AT 和 XA 四种经典事务模式。下图是四种模式的发布时间。
各种模式有其各样的特点:
AT 模式
算是阿里体系独创的事务模式,其本质属于两阶段事务,其二阶段的 commit/rollback 由框架自动生成,对业务没有侵入,用户友好度高于 TCC 模式,可完美接续 Spring 事务,开发效率也较高,也是当前用户最多的一种模式。在 v1.5.2 已经发版的当下时间节点来看,AT 模式下通过全局锁来实现数据的隔离性,对于同一个资源的事务处理只能串行操作,性能一般。
TCC 模式
需要业务层参与者实现 prepare/commit/rollback 接口,其性能在四种模式下最好,数据可见性、隔离性也不错,流行程度仅次于 AT。特别适用于对吞吐、性能、隔离性要求都比较高的金融业务。
SAGA 模式
是一种长事务解决方案,其一阶段正向服务和二阶段补偿服务都由业务开发实现,可以很方便地与微服务框架进行结合,其性能仅次于 TCC 模式。因为其方便编排的特点,它在微服务编排领域有大量应用,当然使用时需要用户写 JSON 文件对服务进行编排。但其数据隔离性不好,业务数据有被脏写的风险。社区目前正在进行 SAGA 注解化工作(https://github.com/seata/seata/pull/4577),可进一步提升其性能与易用性。
XA 模式
不同于其他三种「补偿型」事务,它提供了最严格的隔离性:可以保证全局视角的数据一致性,即保证了用户不会出现脏读。Seata XA 模式的接口与 AT 模式基本一致,算是对用户比较友好的一种事务模式,它是对 XA 协议的严格实现。XA 模式的缺点是其事务范围比较长,其性能最低。
四种模式的发版顺序如下:
每种事务模式在阿里体系内都有各自的业务场景,其出现与演进都是迎合了各自业务场景现有的痛点。AT 和 XA 是不需要理解业务语义的,作用于 DB driver + DB 层面,TCC 和 SAGA 则需要业务层面自实现回滚幂等类逻辑,按照数据面和业务面来切分,依据对业务的入侵程度,四种模式归类如下图。
分布式事务的基石是通信框架、SQL 解析以及数据库连接驱动实现等。得益于 Java 语言丰富的生态,Seata Java 版本可以很方便地站在这些 “巨人” 肩上展开相应的工作,这也是其他语言无法望其项背的。例如,主流数据库都提供了其 Java 版本的 DB driver。但当把工作背景放到多语言场景下时,就需要考量各个语言相关技术点的实现程度了。
四种事务模式,AT 模式本质是应用层的事务,需要把数据库层面做过的 Redo/Undo 在应用层再做一遍,其中非常关键的一个技术点是:AT 模式需要介入数据源做 SQL 拦截,对 SQL 进行解析。单单考量 SQL 解析这个单技术点,Java 和 Python 语言有 antlr,Go 语言有 TiDB 提供的可自由使用的 pingcap/parser,但目前很多其他语言在这块都是空白的。
所以社区在考量现实情况后,除了 Go 和 Python 版本,在进行多语言版本建设时,没有 SQL 解析包的语言版本先不提供 AT 模式的实现。
2. 通信协议
不论哪种事务模式,都构建在 Seata 独有的架构之上。
图片来自 seata 官网
Seata 总体架构由如下角色构成:
事务协调器 Transaction Coordinator
简称 TC,维护全局事务和分支事务的状态,驱动全局事务提交或者回滚。
事务管理器 Transaction Manager
简称 TM,定义全局事务的范围,提交或者回滚全局事务。
资源管理器 Resource Manager
简称 RM,和分支事务在同一个应用,进行分支事务的注册,报告分支事务的状态,驱动分支事务的提交或者回滚。
TC 与 TM 以及各个 RM 之间使用 netty 框架进行长链接通信。具体而言,Seata Java 版本的通信协议是在四层 TCP 协议之上又定义了一套私有的二进制双向通信协议。其关键点在于 Seata Java 版本站在了 netty 这个巨人肩上。
回到多语言这个背景下,很多语言并没有提供一套成熟的 TCP 通信框架。譬如 Dubbo 在建设其 Go 版本 dubbo-go 时,为了在 TCP 之上实现与 Dubbo 的私有二进制协议通信,本人前期的工作重点是先实现 TCP 通信框架 getty(https://github.com/apache/dubbo-getty),然后再实现其序列化协议 dubbo-go-hessian2(https://github.com/apache/dubbo-go-hessian2)。如果把语言切换成 JS、PHP 或者 Python,相关通信协议建设需要耗费社区大量精力。
Seata 2019 年就在 API 层适配了 gRPC 的事务上下文传递,为了方便 Seata 多语言版本的建设,Seata Java 框架本身正在进行一项重要工作:Seata Client (包括 TM 和 RM) 基于 gRPC 与 Seata Server (TC) 集群进行通信。希望借助于 gRPC 的多语言优势,节省多语言版本在通信层面的工作量。
3. 配置和注册中心
类似于其他微服务框架,Seata 自身除了上一节提到的内部组件外,还依赖于注册中心和配置中心。微服务上层的应用通过配置中心找到注册中心,再通过注册中心发现 Seata 的各个服务组件。一个典型的完备的 Seata 服务架构如下图。
Seata Java 这套架构可以很方便的嵌入注入 Dubbo、SOFARPC 以及 Spring 等 Java 微服务框架中。其中两种非常重要的外部依赖组件是:
Config Centre
依据参考文档 1 和 3,配置中心的作用是 “放置着各种配置文件”,客户端通过配置中心的配置 “去读取全局事务开关, 事务会话存储模式” 等事务配置信息。
Seata Java 支持的配置中心类型有 File、Nacos 、Apollo、Zk、Consul、Etcd3 等。
Registry Centre
依据参考文档 2,注册中心记录了服务路由和寻址映射关系。服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址进行调用。比如 Seata Client 端 (TM、RM) 对 Seata Server (TC) 集群进行服务发现就是通过注册中心进行的。
Seata Java 支持的注册中心有 File 、Nacos 、Eureka、Redis、Zk、Consul、Etcd3、SOFA 等。
先不论这套体系的复杂程度与维护成本,在进行 Seata 多语言体系建设时,遇到的关键问题是:这些组件的多语言支持情况参差不齐。Seata 其他语言版本不可能为了支持这些组件,让 Seata 社区自己去构建起这些组件的多语言客户端实现。
愚以为,解决这个问题的手段,不是去裁剪 Seata Java 的现有实现,而是扩展 Seata Java 的功能支持新的更多的配置中心与注册中心。在云原生时代的当下,大部分云平台的底座是 Kubernetes,大部分微服务体系都在基于 K8s 构建其新技术形态。所以 Seata 多语言体系可以用如下形式构建起新的 name server:
使用 K8s 的 ConfigMap 存储 Seata 的配置数据
一般地,Seata 是作为其他微服务平台如 Spring Cloud Alibaba、Dubbo、HSF、SOFARPC 等框架的组件使用的。这些框架本身就有配置中心的概念,支持了 Nacos、Apollo、SOFARegistry 等流行的配置中心,Seata 可以复用这些框架现有的配置中心,减少维护成本。
多语言版本的 Seata 的配置类型可以先实现 File 类型,使用 Seata 的微服务应用运行在 Kubernetes 平台上时,通过 ConfigMap 挂载 Seata 的配置。
使用 K8s 的 API server 或者 DNS 组件充当 Seata 的注册中心
同理于配置中心,Seata 的注册中心也可以复用其所在的微服务框架的注册中心,如 Nacos、Etcd、Zookeeper 等。运行在 Kubernetes 平台上时,把 API server 当作注册中心,多语言版本的 Seata 优先实现 File 类型,配置 API server 地址即可。
Seata server (就是 TC) 可以多 namespace 部署,每个 namespace 下可以有多个 TC 集群,Seata Client (包括 TM 和 RM) 可以通过 service 形式获取 TC 集群地址,这样既达到了 TC 高可用的目的,也方便在客户端层面对 TC 集群进行负载均衡。
PART. 2--总结
通过对事务模式、通信协议以及配置与注册中心的讨论,可以看到,在进行 Seata 多语言体系建设时,并不是让 Seata 多语言实现完全以 Seata Java 版本为参照向其靠拢,而是 Seata Java 版本作为 Seata 多语言体系的一部分共同进化。
PART. 3--整体工作进度
计算机行业有个 TIOBE 排行榜,定期更新各种主流计算机语言的流行度。参照这个排行榜中前 10 大流行语言,本人月初 (2022 年 7 月) 在 Seata 两大钉钉群发起了 Seata 多语言投票,统计结果如下:
根据投票结果以及社区相关人才技术储备情况,社区决定先重点投入 Go、Python、JS 三种语言建设上。几种语言当前工作推进情况如下:
seata-go
项目地址:https://github.com/seata/seata-go
社区钉群:33069364
seata-python
项目地址:https://github.com/opentrx/seata-python
社区钉群:44788121
seata-js
项目地址:https://github.com/seata/seata-js
社区钉群:44788119
seata-rust
项目地址:https://github.com/seata/seata-rust
社区钉群:44791799
seata-php
项目地址:https://github.com/seata/seata-php
社区钉群:44788115
历史上,Seata 曾经有两个 Go 版本,分别是 2019 年由张旭贡献的 seata-go 和 2020 年由刘晓敏贡献的 seata-golang。为了统一建设,目前已经把这两个项目合并,seata-go 完成度是多语言版本中最高的,实现了 TCC 和 AT 模式。目前 XA 和 Saga 模式的实现也在推进中,预计秋季可发布第一个版本。其次完成度比较高的是 seata-python,提供了 AT 事务模式。
考虑到 Seata 目前大部分开发者和用户都在国内,Seata 社区建设了多个语言社区群,以推进语言版本的开发工作。
Seata 多语言体系建设工作目前正在如火如荼地展开中,欢迎行业同仁入群参与其中,与我们一起推动 Seata 各个语言版本的实现,提升各个语言微服务框架的事务技术水平,开创分布式技术建设新局面!
【参考文档】
1. Seata 应用侧启动过程剖析——注册中心与配置中心模块:
https://seata.io/zh-cn/blog/seata-client-start-analysis-02.html
2. Seata 注册中心实现原理:
https://seata.io/zh-cn/blog/seata-config-center.html
3. Seata 配置中心实现原理:
https://seata.io/zh-cn/docs/user/registry/index.html
4. Seata 企业版: