关键词:
点击上方“朱小厮的博客”,选择“设为星标”
后台回复"书",获取
后台回复“k8s”,可领取k8s资料
在单体应用向微服务架构转型的过程中,本地事务已不再满足系统一致性需求,为了解决这一问题,前人在对性能和数据一致性反复权衡的过程中总结了许多典型的协议和算法,各有优劣。本文我们将深入探讨 Freewheel 如何实现无单点故障的可扩展分布式事务实现模型。
1为什么需要分布式事务?
当应用程序有严格的数据一致性要求时,ACID 事务是必须的,如果一个事务涉及的所有操作能够放在一个服务内部,且共用一个数据库,那么只用在一个方法里同一个事务下操作数据库即可。然而为了提升系统整体的可靠性,方便各个模块独立演化,系统从单体应用演进为微服务架构。随着数据体量的增长,数据源也从 MySQL 扩展到关系型数据库 Amazon Aurora 和 NoSQL 数据库 (Amazon DynamoDB),基于多样化索引和查询数据的需求,引入了搜素引擎 (ApacheSolr 和 ElasticSearch ) ,多服务交互、多数据源并存产生了分布式事务。
Freewheel 分布式事务应用场景有三个:
多服务,同数据源: 业务单元跨越多个独立服务,服务访问同一个数据源,如 MySQL。
单服务,不同数据源: 业务单元涉及一个独立服务,但这个服务访问多个数据源,如 MySQL,DynamoDB。
多服务,不同数据源: 业务单元跨越多个独立服务,每个服务访问不同数据源,如 MySQL,DynamoDB。
综合考虑 Freewheel 的业务需求后,我们实现了多引擎数据库分布式事务。
2多引擎数据库分布式事务设计
Freewheel 分布式事务方案主要设计目标如下:
数据强一致性: 确保该事务范围内的所有操作都可以全部成功或者全部失败,事务具有原子性、一致性、隔离性、持久性 4 个特性。
Atomicity(原子性):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复到事务开始前的状态,就像这个事务从来没有执行过一样。
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。完整性包括外键约束、应用定义等约束不会被破坏。
Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
系统高可用: 遵循“design for failure”的设计原则,硬件层面,采用服务节点多 region 多 AZ 部署和节点故障快速自恢复的策略来保证系统的高可用。软件层面,设计 failover 机制应对服务异常。
可扩展: 应用 Auto Scaling 服务,它会基于设定的负载压力,自动进行扩展和缩容,来保证服务正常运行。
易用性: 分布式事务应用 API:易学,易懂,易记,系统设计上无业务侵入,没有额外的编码或测试工作。
3多引擎数据库分布式事务技术选型
常见分布式事务解决方案对照表:
结合 Freewheel 强一致性业务需求,多数据源分布式事务将由 XA、2PC 和 Seata 这些解决方案组合而成。
Seata 框架设计思想
基于 XA 的 Aurora 分支事务
基于 2PC 的 DynamoDB 分支事务
4多数据源分布式事务解决方案
架构解析
Freewheel 分布式事务依托在 Freewheel 数据访问层中间件 (DAL) 上,这个中间件是由 Freewheel 平台团队自主研发的,它的目标是为上游应用提供更好的数据访问,为下游数据源提供更好的保护。为了方便描述,下文均用 DAL 来作为 Freewheel 数据访问层中间件的简称。
分布式事务由这三个组件来协商处理:
Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
Transaction Manager (TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
Resource Manager (RM): 控制分支事务,负责分支注册、并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。
为了预防死锁,并且减少 DAL RM 和 TC 之间的 交互,降低对 TC 的依赖,同一个分布式事务操作放在同一个 DAL 节点,由此,DAL RM 可以方便的在单节点控制和协调分支事务,完成全局事务的提交和回滚。
以多服务,不同数据源 (Aurora 与 DynamoDB) 为例,描述 Freewheel 分布式事务过程。
A Service TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。
XID 在微服务调用链路的上下文中传播。
TM 向 TC 发起针对 XID 的全局提交或回滚决议。
TC 向 DAL RM 发起全局提交或回滚决议。
DAL RM 对 XID 下管辖的全部分支事务完成提交或回滚请求。
数据访问层资源管理器 (DAL RM) 实现
基于业务需求,DAL 分布式事务支持的数据源为 MySQL 和 AWS DynamoDB,下面章节阐述了这两个数据源 ACID 技术实现。
分布式事务设计中新建了事务控制表、事务记录表、索引表及业务镜像表:
事务控制表:记录事务运行状态开始、提交、回滚。
事务记录表:存储正在发生事务信息。
索引表:记录记录主键 ID, 用于实现排它性对其他事务更新与普通更新。
业务镜像表:存储业务原值。
Aurora/MySQL
采用 MySQL XA 2PC 来保证 ACID,原因如下:
Mysql 5.7 版本已经支持 XA,目前 Aurora 也是 Mysql 5.7.x。
XA 强一致性。
不侵入业务,这会减少业务方的工作量。
这个时序图描述了 RM 对 MySQL 事务的工作流程:
一个事务操作,由同一个 DAL RM 处理,相同 DB 下业务事务处理,放在一个 XA 操作里:
节省 XA 连接 fd。
减少 DAL RM 和 Aurora 之间的 XA 交互次数。
避免多个 XA 分支事务上的数据操作冲突。
SQL CRUD 语句应该使用触发行锁的索引操作,否则会触发表锁,影响系统吞吐量。
AWS DynamoDB
DynamoDB 提供了本地事务接口 TransactGetItems 和 TransactWriteItems, 它等效于 MySQL 批量操作,对于相互间有上下文或者依赖的操作并不可用,这限制了它在应用中的使用场景,详细信息请参考 TransactGetItems 和 TransactWriteItems。
DynamoDB 本身没有分布式事务机制,DAL 结合 DynamoDB 功能属性,对提供的插入、更新、删除和查询接口,设计 2PC 机制 来满足 DynamoDB 的 事务属性。
下表显示了分布式事务操作 (DisTxDAL) 和其他操作之间的隔离级别。
更新接口实现方法
一阶段
应用本地事务原子地备份事务记录及备份索引
应用本地事务原子地更新附加事务信息业务值及备份业务原值到镜像表
二阶段
如果决议是提交,应用本地事务原子地移除业务记录事务属性、删除镜像记录、删除备份事务记录
如果决议是回滚,应用本地事务原子地恢复业务记录、删除镜像记录、删除备份事务记录
插入接口实现方法
一阶段
应用本地事务原子地备份事务记录及备份索引
插入带有事务属性信息的业务记录
二阶段
如果决议是提交,应用本地事务原子地移除业务事务属性、删除备份记录
如果决议是回滚,应用本地事务原子地删除业务记录、删除备份记录
删除接口实现方法
一阶段
应用本地事务原子地备份事物记录及备份索引
更新带有事务属性信息的业务记录, 标注为删除操作
二阶段
如果决议是提交,应用本地事务原子地删除事务记录、删除业务记录
如果决议是回滚,应用本地事务原子地恢复业务记录、删除备份记录
查询接口实现方法
事务进行中的数据含有事务属性信息,xid 表示事务全局事务 ID, operation 表示事务操作接口 create、update、delete,这里 item 表示业务数据元素。
基于业务数据变更表及写接口实现方法,实现了在读提交与读未提及查询方法:
判断记录是否含有事务属性,如果无,返回记录,否则到步骤 2
判读隔离级别,如果读提交,步骤 3,如果读未提交,步骤 5
记录事务操作是 create, 返回空,否则如果是 delete,去除事物属性信息,然后返回,否则步骤 4
本地事务原子地读取镜像表与业务表,如果镜像表值存在,返回,否则返回业务表值,都不存在返回空
如果记录事务操作是 delete,返回空,否则返回记录
数据访问层事务管理器 (DAL TM) 实现
为了方便用户使用,分布式事务 API 里封装了与事务协调器及 DAL 资源管理器的交互过程,交互过程对应用是透明的,下面是分布式事务 API:
type DistributedTransApi interface
DisTxDAL(ctx context.Context, fn TranFunc) error
type TranFunc func(ctx context.Context) error
微服务之间,微服务与数据库访问层之间采用 google rpc 调用,服务之间关键数据都是基于 context metadata,如果经过两层服务交互, 就会导致 context metadata 丢失。举例来说,A 服务调用 B 服务,B 服务调用 C 服务,那么 C 服务就会缺失 A 服务 context metadata,针对这种情况,DAL 提供了通用函数用于提取 DAL 相关的元数据,供应用方按需添加。
func ExtractDalMetadata(ctx context.Context) (metadata.MD, error)
数据访问层事务协调器 (DAL TC) 实现
协调器主要功能点:
分配事务 XID,维护全局事务的运行状态,负责协调和驱动全局事务的提交或回滚;
故障转移:提交 / 回滚。
分配事务 XID
全局分配唯一事务 ID,供 DAL TM 获取,此数据需要在同一事务的业务服务间传输共享。
事务协调
维护全局事务的运行状态,负责协调和驱动全局事务的提交或回滚。
故障转移
DAL TC 是 HA 多节点实例,引入 ETCD leader 选举机制来保证只有一个 TC 实例承担 failover 功能,详细信息在系统高可用章节软件层面 failover。
系统高可用
硬件层面
为了预防硬件故障对高可用的影响,DAL,TC 和 ETCD 服务均是多 Region 多 AZ 部署,并且基于服务的特性配置了相应的服务策略:
ETCD 采用自恢复策略
DAL 和 TC 服务采用了弹性伸缩策略
美东美西均部署相应服务作为服务灾备策略,下图是美东地区的解释图(美西类似)。
软件层面 Failover
在 DAL 应用或者业务应用遇到异常退出时,软件层面 Failover 机制是为了能不发生死锁,并且继续处理未完成分布式事务,实现方法如下:
DAL TM 接口添加超时控制,由应用设置事务的超时时间,默认是 60 秒
DAL RM 在事物开始、提交或者回滚阶段存储 xid 信息,如过期时间,运行状态等,在业务接口调用里存储业务处理记录
DAL TC 轮询地从事务控制表里获取超时事务。基于事务状态处理:如果 start or rollback:触发 Rollback,如果 commit:触发 commit
5未来展望
Freewheel 强一致性分布式事务未来会支撑更多的数据源,如 Redis、Solr 和 ElasticSearch 等,目前的数据库访问层 API 是基于 gRPC,这对数据库访问层使用方带来了一定技术语言限制,未来会探究 GraphQL 在数据库访问层分布式事务应用的可行性。
想知道更多?扫描下面的二维码关注我后台回复"技术",加入技术群
后台回复“k8s”,可领取k8s资料
【精彩推荐】
浅谈分布式事务
...务端非常可能是由多个服务和数据库实例协同完成的。在一致性要求较高的场景下,多个独立操作之间的一致性问题显得格外棘手。基于水平扩容能力和成本考虑,传统的强一致的解决方案(e.g.单机事务)纷纷被抛弃。其理论... 查看详情
浅谈分布式事务(转)
...务端非常可能是由多个服务和数据库实例协同完成的。在一致性要求较高的场景下,多个独立操作之间的一致性问题显得格外棘手。基于水平扩容能力和成本考虑,传统的强一致的解决方案(e.g.单机事务)纷纷被抛弃。其理论... 查看详情
zookeeper概念(代码片段)
...于对Paxos算法实现,该框架保证了分布式环境中数据的强一致性,也正是基于这样的特性,使得Zookeeper可以解决很多分布式问题。 它可以实现的功能有丰富。数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管... 查看详情
分布式基础理论之cap和base
前言本文聊聊CAP定理和BASE理论。CAP定理C:一致性(Consistency)数据的强一致性。希望分布式系统只读到最新写入的数据A:可用性(Availability)分布式系统能提供服务就行,数据的不一致可以忍受P:分区容错性(Partitiontolerance)分布... 查看详情
zookeeper应用场景
...Paxos算法的实现,使该框架保证了分布式环境中数据的强一致性,也正是基于这样的特性,使得ZooKeeper解决很多分布式问题。网上对ZK的应用场景也有不少介绍,本文将结合作者身边的项目例子,系统地对ZK的应用场景进行一个分... 查看详情
zookeeper典型应用场景
...Paxos算法的实现,使该框架保证了分布式环境中数据的强一致性,也正是基于这样的特性,使得ZooKeeper解决很多分布式问题。网上对ZK的应用场景也有不少介绍,本文将结合作者身边的项目例子,系统地对ZK的应用场景进行一个分... 查看详情
dddcqrs架构和传统架构的优缺点比较
...可以完美的结合,发挥CQRS这个架构的最大价值。数据一致性传统架构,数据一般是强一致性的,我们通常会使用数据库事务保证一次操作的所有数据修改都在一个数据库事务里,从而保证了数据的强一致性。在分... 查看详情
分布式事务
...,和传统的事物ACID特性是相反的,它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但同时,在实际的分布式场景中,不同业务单元和组件对... 查看详情
分布式基础理论之cap和base
前言本文聊聊CAP定理和BASE理论。CAP定理C:一致性(Consistency)数据的强一致性。希望分布式系统只读到最新写入的数据A:可用性(Availability)分布式系统能提供服务就行,数据的不一致可以忍受P:分区容错性(Partitiontolerance)分布... 查看详情
zookeeper—应用场景(代码片段)
...s算法的实现,使该框架保证了分布式环境中数据的强一致性,也正是基于这样的特性,使得ZooKeeper解决很多分布式问题。本文介绍zk的应用场景。zk并非天生就是为这些应用场景设计的,都是后来众多开发者根据... 查看详情
分布式事物一致性设计思路(代码片段)
...了,统一提交,失败回滚,严格保证了同一事务内数据的一致性!而分布式事务不能实现这种ACID,它只能实现CAP原则里的某两个,CAP也是分布式事务的一个广泛被应用的原型,CAP(Consistency,Availability,PartitionTolerance),阐述了一个分... 查看详情
DynamoDB 是不是仍然遵循 CAP 定理及其“强一致性”承诺?
】DynamoDB是不是仍然遵循CAP定理及其“强一致性”承诺?【英文标题】:IsDynamoDBstillfollowingCAPtheoremwithits"StrongConsistency"promises?DynamoDB是否仍然遵循CAP定理及其“强一致性”承诺?【发布时间】:2015-12-0207:12:59【问题描述】... 查看详情
解决分布式一致性问题的基础理论
...D,一般关系型数据库都会保证ACID这个特性,那么ACID对于一致性来说,就是一种最直接且最有效的强一致性。如果在数据量较小的情况下,可以利用关系型数据库的强一致性解决。面对具有大规模、高并发的特性,必须采用对高... 查看详情
数据库的强一致性和弱一致性
强一致性可以理解为在任意时刻,所有节点中的数据是一样的。同一时间点,你在节点A中获取到key1的值与在节点B中获取到key1的值应该都是一样的弱一致性(相当于异步)系统并不保证续进程或者线程的访问都会返回最新的更... 查看详情
分布式共识算法——gossip协议(图解)
...的应该都是Raft、Paxos、Zab算法这类理解起来比较困难的强一致性算法。但是还有一个弱一致性的共识算法比较好理解,Gossip协议。与Paxos和Raft目标是强一致性不同 查看详情
分布式共识算法——gossip协议(图解)
...的应该都是Raft、Paxos、Zab算法这类理解起来比较困难的强一致性算法。但是还有一个弱一致性的共识算法比较好理解,Gossip协议。与Paxos和Raft目标是强一致性不同 查看详情
matlab代码:基于多智能体系统一致性算法的电力系统分布式经济调度策略
MATLAB代码:基于多智能体系统一致性算法的电力系统分布式经济调度策略关键词:一致性算法多智能体分布式调度仿真平台:MATLAB平台参考文档:中文复现,效果非常好,想看文献和运行效果加好友主要内... 查看详情
分布式锁与实现——基于redis实现
...大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partitiont... 查看详情