7

事件驱动的分布式事务架构设计

 1 year ago
source link: https://developer.51cto.com/article/710613.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、什么是事件驱动架构

事件驱动架构是一种促进生产的 软件架构范式 。事件驱动架构在用微服务构建的现代应用中非常普遍,它用事件来触发、解耦服务之间的通信。事件可以是 状态的变更 ,比如将商品放入购物车;也可以是 某种标识 ,比如订单的发货通知。

116541f77e843f2a0aa662db9f0889d4418743.png

在传统的软件架构中,应用逻辑是通过请求、过程驱动的。一个请求执行一段逻辑同步返回一个响应,在业务逻辑中,将要执行的代码按照过程顺序进行编排。

而事件驱动架构中,事件消费者会以 异步 的方式处理事件生产者产生的事件,原来过程当中的逻辑交给事件消费者去处理,解开服务之间的耦合,使应用的逻辑聚焦,应用的 职责单一 , 代码更加简洁 ,也能 提升系统的响应能力 。

二、分布式事务的事件驱动架构

在 2020 年,本文作者开源了 Go 语言的分布式事务框架 Seata-Golang。Seata-Golang 实现 AT 模式和 TCC 模式,这两种模式都是过程驱动。

到了 2022 年,随着对云原生技术的理解深入,从 Kubernetes Control-Loop 思想中获得灵感,全新设计了高性能、无侵入、事件驱动的 Go 语言分布式事务框架 hptx ,以及支持跨语言分布式事务、读写分离、分库分表的 Mesh 方案 DBPack 。这两款产品都能解决分布式事务问题, 前者只支持 Go 语言 , 后者支持任意编程语言 。他们采用了相同的事件驱动架构。下面进行详细的说明。

150bc67947f93dfd589440017bc841c487846e.png

在 Seata 的设计中,事务发起者发起全局提交后,首先会判断该事务是否允许异步提交,如果允许,则直接返回提交成功,然后 由  ​AsyncCommittingSessionManager​ 来异步地通知每个分支事务提交,AT 事务默认允许异步提交。

如果不允许异步提交,事务协调者会依次通知全局事务参与者即每个分支事务提交,所有分支事务提交成功后,同步返回给事务发起者全局事务提交的结果,如上图。事务协调者通知事务参与者提交过程中发生了异常,会将该全局事务标记为  CommitRetrying​ 状态,将会有一个  RetryCommittingSessionManager 定时从持久存储中捞取标记的全局事务重试提交。

全局回滚的过程与上图类似,全局回滚时,AT 模式和 TCC 模式都是同步执行,依次通知每个分支事务回滚,然后再响应回滚结果给事务发起者。如果回滚失败,则将全局事务标记为 RollbackRetrying​ ,由  RetryRollbackingSessionManager 定时捞取标记的全局事务数据重试回滚。

3852325839b6d6c7281830a3a94a9848fe1a0c.png

Seata-Golang 的用户经常会问一个问题,事务协调者 TC Server 怎么做高可用?

Seata 包括 Seata-Golang 默认推荐使用 Mysql 数据库作为 TC 状态数据的持久化存储。TC Server 本身则是无状态应用,可以部署多个副本,但这里就存在一个问题:多个对等副本里的 

AsyncCommittingSessionManager​ 、 RetryCommittingSessionManager​ 、 RetryRollbackingSessionManager  都会从数据库去捞取对应的数据执行,会导致事务的提交、回滚重复执行,虽然 AT 模式天然做到幂等,TCC 模式由用户保证幂等,但总是存在一定的资源浪费,且不够优雅。

31cf76222294fb1e4e65260925f28a166da8b9.gif

上图展示了 hptx 和 dbpack 的事务协调逻辑,事务发起者 AggregationSvc 发起全局事务提交、回滚,仅仅是修改 ETCD 中的数据状态,然后立即返回。订单服务和商品服务使用前缀  bs/${appid}​  Watch 存储在 ETCD 中的分支事务数据,当分支事务的数据发生过变更后,ETCD 马上推送一个变更事件给相应服务,订单服务和商品服务收到变更事件后,将数据加入  workqueue  去执行提交或回滚的逻辑。

AggregationSvc 提交、回滚时不会调用 OrderSvc、ProductSvc 的接口,整个过程通过 ETCD 解耦后异步执行。

f11e8dc53f52eb3b9da508807b945374b06077.png

事务分支提交或者回滚失败后,会重新进入到 workqueue​ 当中继续消费,直至提交、回滚成功,或回滚超时(AT 模式回滚操作涉及到全局锁的释放,需要设置超时时间,即  retry_dead_threshold )。

33a07f106b9826367b6740581aefe2b210dc0b.png

在这个架构中,已经没有中心化事务协调者 TC Server,用户只需要关心自身应用的高可用,如果应用多副本部署,hptx 和 dbpack 会通过 etcd 选主,只有选为 master 的副本才能 watch 自身产生的分支事务数据去做提交、回滚,避免了提交、回滚逻辑重复执行的问题。

集成 hptx,只需要依赖相应的 sdk,而不需要部署额外的 TC Server,但状态数据的存储由原来的 Mysql 换成了 ETCD。

三、新架构带来的好处

全新的、云原生的、事件驱动架构,更加简洁,性能更强。采用 hptx 的应用事务协调性能比 Seata-Golang 提升 1 倍,通过 dbpack 以 mesh 方式协调分布式事务性能比 seata-golang 提升了百分之 50。下面是一些测试数据:

seata-golang

2018 款 Mac book pro

每秒 18.54 笔事务

2018 款 Mac book pro

每秒 38.89 笔事务

dbpack

2018 款 Mac book pro

每秒 28.09 笔事务

阿里云 ecs ecs.sn1ne.xlarge (4 核 8G)

每秒 35.15 笔事务

hptx 是当前性能最强的云原生、无侵入分布式事务解决方案,选择其他内存型存储组件理论上可以得到更高的性能,但综合可靠性和性能,ETCD 是目前最好的选择。

经过持续地在分布式事务领域的研究总结,使分布式事务框架不断进化,从最初的兼容 java seata 的 seata-golang v1 版本,到云原生的、无侵入的、基于 grpc 的 seata-golang v2 版本,到基于 ETCD watch 机制的、事件驱动的 hptx,再到跨语言的 dbpack,分布式事务一直在进化,能力也在进一步增强。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK