陆敬尚

Apache ShardingSphere Committer,SphereEx 基础设施研发工程师,热爱开源,热爱数据库技术,目前专注于 Apache ShardingSphere 事务模块的开发。

背景

随着业务的快速发展,数据的不断膨胀,流量负载的增加,业务系统遇到了强烈的挑战,对数据库系统可扩展性提出了强烈的诉求。Oracle、MySQL、SQL Server、PostgreSQL 传统单机数据库在线扩展上的问题日益凸显。为了解决扩展问题,出现了可水平扩展的分布式数据库,于是分布式事务问题成为了必须面对的问题。

在这种背景下,ShardingSphere 提供了一套分布式数据库增强计算引擎,通过可插拔架构构建基于数据库之上的生态系统,提供了分布式事务的能力。

事务介绍

事务语义

事务语义定义了四个特性:原子性(Atomicity)、持久性(Durability)、一致性(Consistency)、隔离性(Isolatation)。

原子性(Atomicity)

在分布式场景下,一个事务的操作可能分布在多个物理节点上,保证在多个节点上的操作都成功,或都不成功。

持久性(Durability)

事务提交后,即使断电,事务的操作也是有效的。

一致性(Consistency)

注意:不是 CAP 理论中 C,CAP 中的 C 指的是多副本之间的数据一致问题,这里是不同层次的抽象。

站在用户的角度,数据从一个状态,转移到另外一个状态,两个状态都满足一定的约束。比如:

银行账户数据,账户 A 有 500 元,账户 B 有 500 元,总额 1000,在一个事务中,执行完 A 和 B 的转账操作后,A 和 B 的账户总额还是 1000。

隔离性(Isolatation)

事务并发执行时,保证并发时数据的正确性。比如:两个事务同时修改一条数据,保证两个事务按一定顺序执行,使数据保持在一个正确的状态。

面临的挑战

分布式事务相对单机事务来说面临下面的挑战:

1. 原子性,对于单机事务来说,使用 undo log 和 redo log 就可以保证全部提交或者全部回滚。而分布式事务涉及多个物理节点,每个节点情况是不同的,有的节点日志写成功,有的节点日志写不成功。

2. 网络的不稳定,对于单机来说,通讯是稳定的,任何操作都可以得到回复,不论成功与失败。而分布式场景下,网络是不稳定的,有可能一个操作是得不到回复的,怎样保证分布式事务的可用性(异常事务的清理、恢复等)是一个问题。

3. 并发控制,随着 MVCC 的出现,操作的可线性化(linearizable)成为了刚需。在单机数据库中,可以很容易地产生全局单调递增的事务号,在分布式场景中则不然。

解决方案

原子提交

针对原子性和网络不稳定问题,目前主流的解决方案是 2PC,2PC 定义了两个角色 TM(Transaction Manager)、RM(Resource Manager)。

在分布式场景下,一个事务的操作可能分布在多个节点上,整个事务分两个阶段。

1. 第一阶段,RM 锁定相关资源并执行具体操作,返回成功与否给 TM。

2. 第二阶段,TM 更具第一阶段 RM 返回的结果,如果全部成功,执行最后的提交操作(事务状态的更改,锁状态删除等),如果有失败的,则回滚。

说明:当然会有一些优化点,比如不涉及多节点的事务转化为一阶段提交等。

注意:两阶段提交协议只解决了提交的问题,要么提交成功,要么不成功,不存在部分成功的中间状态。和事务隔离级别没有必然关系。

并发控制

并发控制,就是保证并发执行的事务在某一种隔离级别上的执行策略。自从多版本控制(MVCC)出现,主流数据库基本抛弃了以前的两阶段锁模型。

并发控制本质是对数据读和写的并发的控制。并发控制的策略决定了隔离级别,并发控制要解决两个问题。

1. 决定并发的粒度,比如 MySQL 有行锁(粒度为一行),表锁(粒度为一个表)等

2. 三种并发场景的行为:

a. 读读并发,不需要特殊处理,因为不涉及数据的变更。

b. 写写并发,不能同时并发,否则会产生数据混乱。

c. 读写并发,性能优化主要在这里做,有多种并发控制机制,基本都选择了多版本并发控制(MVCC)。

MVCC 并发控制模型

现有主流实现方式有两种:

  • 基于事务 ID 和 ReadView

每次事务获取事务 ID,标识事务的开启顺序,通过活跃事务列表来获取快照,存储多个以事务 ID 为版本的数据,从而达到并发控制的效果。MySQL、Postgres-XL 都是采取的这种方案。

  • 基于 timestamp

引入 timestamp,通过在数据中添加 timestamp 相关属性,通过对比数据的 commitTs(commit timestamp) 和 Snapshot timestamp 来判断可见性,从而达到可线性化的并发控制效果。Spanner 采用的这种方案。

上面两种方案都离不开全局事务号的生成,常见的全局事务号生成机制有 TrueTime(Spanner 采用),HLC(CockroachDB 采用有误差的 HLC),TSO(Timestamp Oracle),详细原理见参考文献。

ShardingSphere 事务设计

ShardingSphere 事务功能建立在存储 DB 的本地事务之上,提供 LOCAL、XA、BASE 三种模式事务,使用者只需使用原生事务方式(begin/commit/rollback),就可以使用三种模式,在一致性和性能做合适的权衡。

LOCAL

LOCAL 模式直接建立在存储 DB 的本地事务上的,会存在一定的原子性问题,当然性能是最高的,如果可以容忍这个问题,这将是一个不错的选择。

XA

XA 模式,XA 协议是基于 2PC 定义的一套交互协议,定义了 xa start/prepare/end/commit/rollback 等接口,常用的实现有 Narayana、Atomics, ShardingSphere 集成了 Narayana、Atomics 的 XA 实现。

1. app 连接到 Proxy 上,Proxy 创建一个 session 的对象和这个 connection 绑定。

2. app 执行 begin,Proxy 通过 Narayana TM 新建一个逻辑 transaction,和当前 session 绑定。

3. app 执行具体 SQL,session 负责建立到存储 DB 的 connection,并把 connection 通过 Transaction.enlistResource() 接口把 connection 注册到 transaction,执行 XA START {XID} 开启事务,并执行路由改写后的 SQL。

1. app 执行 commit 命令,transaction 中注册的连接存储 DB 的 connection,分别执行 xa prepare,当所有 connection 返回 ok,更新 transaction 状态为 prepared,每个 connection 执行 xa commit,都返回 ok 更新 transaction 状态为 commited,提交成功。如果 prepare 过程部分失败,用户可以通过 rollback 命令出发回滚,不处理则有后台进程进行清理。

2. app 执行 rollback 命令,transaction 中注册的连接存储 DB 的 connection,分别执行 xa rollback,进行回滚。

BASE

Base(Basically Available, Soft State, Eventually Consistent)模式,BASE 事务是 CAP 理论中 C 和 A 权衡的结果,Seata 的 AT 模式是 Base 事务的一种实现,ShardingSphere 集成了 Seata 的 AT 实现。

1. app 连接到 Proxy 上,Proxy 创建一个 session 的对象和这个 connection 绑定。

2. app 执行 begin,Proxy 通过 Seata TM 新建一个逻辑 transaction,和当前 session 绑定,并注册到 Seata Server。

3. app 执行一条逻辑 SQL,session 负责建立到存储 DB 的 connection,每个 connection 是 Seata 的 ConnectionProxy 实例,对路由改写后的 actual sql 进行解析, 做一些拦截,比如:如果是修改操作,执行 begin 获取本地锁,执行一条 SQL, 执行 commit 释放本地锁,上报分支事务结果到 Seata Server。

4. app 执行 commit 命令,Proxy 中的 Seata TM 通知 Seata Server 后,直接返回 app,Seata Server 异步和 Proxy 交互,进行删除事务日志。

5. app 执行 rollback 命令,Proxy 中的 Seata TM 通知 Seata Server 后,直接返回 app,Seata Server 异步和 Proxy 交互,执行补偿操作,删除事务日志。

详细流程参考 Seata 官网。

使用示例

安装包准备

以支持较好的 XA,集成 Narayana 的实现为例,进行介绍。由于 Narayana 的 License 问题,不能直接打包到安装包内,需要添加额外的依赖。

根据官网下载好安装包,解压到 ${ShardingSphere} 目录,往 ${ShardingSphere}/lib 目录下添加以下 jar 包。(下载地址:https://mvnrepository.com/)

jta-5.12.4.Final.jar
arjuna-5.12.4.Final.jar
common-5.12.4.Final.jar
jboss-connector-api_1.7_spec-1.0.0.Final.jar                                             | ------------------------------------------------------------------------------------------------------------------------------------
jboss-logging-3.2.1.Final.jar                                                    | ------------------------------------------------------------------------------------------------------------------------------------
jboss-transaction-api_1.2_spec-1.0.0.Alpha3.jar                                           | ------------------------------------------------------------------------------------------------------------------------------------
jboss-transaction-spi-7.6.0.Final.jar
mysql-connector-java-5.1.47.jar                                                   | ------------------------------------------------------------------------------------------------------------------------------------
narayana-jts-integration-5.12.4.Final.jar
shardingsphere-transaction-xa-narayana-5.1.1-SNAPSHOT.jar

MySQL 实例准备

1. 准备两个 MySQL 实例,127.0.0.1:3306,127.0.0.1:3307。

2. 两个 MySQL 实例分别创建用户 root, 密码为 12345678。

3. 两个 MySQL 实例分别创建 test 库。

ShardingSphere-Proxy 配置

修改 server.yaml 事务配置

rules:- !AUTHORITYusers:- root@%:root- sharding@:shardingprovider:type: ALL_PRIVILEGES_PERMITTED- !TRANSACTIONdefaultType: XAproviderType: Narayana

修改 conf/conf-sharding.yaml

dataSources:ds_0:url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=falseusername: rootpassword: 12345678connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_1:url: jdbc:mysql://127.0.0.1:3307/test?serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=falseusername: rootpassword: 12345678connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1rules:- !SHARDINGtables:account:actualDataNodes: ds_${0..1}.account${0..1}tableStrategy:standard:shardingColumn: idshardingAlgorithmName: account_inlinekeyGenerateStrategy:column: idkeyGeneratorName: snowflakedefaultDatabaseStrategy:standard:shardingColumn: idshardingAlgorithmName: database_inlinedefaultTableStrategy:none:shardingAlgorithms:database_inline:type: INLINEprops:algorithm-expression: ds_${id % 2}account_inline:type: INLINEprops:algorithm-expression: account${id % 2}keyGenerators:snowflake:type: SNOWFLAKEprops:worker-id: 123

启动 ShardingSphere-Proxy

参考如下命令启动 Proxy:

cd ${ShardingSphere}
./bin/start.sh

使用 ShardingSphere-Proxy

使用 MySQL Client 连接 ShardingSphere-Proxy 进行测试,参考如下命令。

mysql -h127.0.0.1 -P3307 -uroot -proot
mysql> use sharding_db;
Database changed
mysql> create table account(id int, balance float ,transaction_id int);
Query OK, 0 rows affected (0.12 sec)mysql> select * from account;
Empty set (0.02 sec)mysql> begin;
Query OK, 0 rows affected (0.09 sec)mysql> insert into account(id, balance, transaction_id) values(1,1,1),(2,2,2);
Query OK, 2 rows affected (0.53 sec)mysql> select * from account;
+------+---------+----------------+
| id  | balance | transaction_id |
+------+---------+----------------+
|  2 |   2.0 |       2 |
|  1 |   1.0 |       1 |
+------+---------+----------------+
2 rows in set (0.03 sec)mysql> commit;
Query OK, 0 rows affected (0.05 sec)mysql> select * from account;
+------+---------+----------------+
| id  | balance | transaction_id |
+------+---------+----------------+
|  2 |   2.0 |       2 |
|  1 |   1.0 |       1 |
+------+---------+----------------+
2 rows in set (0.02 sec)

未来规划

现在 ShardingSphere 的分布式事务集成了第三方的 2PC 实现方案,提供了原子性的保证,隔离性依赖于存储 DB 的隔离保证,提供了可用的事务功能。未来基于全局 Timestamp 实现 MVCC,结合 2PC,对事务隔离语义提供更好的支持。欢迎大家关注 ShardingSphere 的成长。

如果大家对 Apache ShardingSphere 有任何疑问或建议,欢迎在 GitHub issue 列表提出,或可前往中文社区交流讨论。

GitHub issue:https://github.com/apache/shardingsphere/issues

贡献指南:https://shardingsphere.apache.org/community/cn/contribute/

中文社区:https://community.sphere-ex.com/

参考文献

1.ACID wiki:https://en.wikipedia.org/wiki/ACID

2.ANSI isolation levels:https://renenyffenegger.ch/notes/development/databases/SQL/transaction/isolation-level

3.《Distributed Transactions Are Evil》:https://wiki.c2.com/?DistributedTransactionsAreEvil

4.《Distributed transactions and why you should care》:https://towardsdatascience.com/distributed-transactions-and-why-you-should-care-116b6da8d72

5.《Fault-Tolerant Stream Processing at Internet Scale》:http://static.googleusercontent.com/media/research.google.com/en/us/pubs/archive/41378.pdf

6.《Oracle Two Phase Commit 2PC Tips》:http://www.dba-oracle.com/t_two_phase_commit_2pc.htm

7.《2PC: Concurrency Control and Recovery in Database Systems》:https://courses.cs.washington.edu/courses/cse551/09au/papers/CSE550BHG-Ch7.pdf

8.《An Empirical Evaluation of In-Memory Multi-Version Concurrency Control》:https://15721.courses.cs.cmu.edu/spring2018/papers/05-mvcc1/wu-vldb2017.pdf

9.《Concurrency Control And Recovery In Database Systems》:https://courses.cs.washington.edu/courses/cse551/09au/papers/CSE550BHG-Ch7.pdf

10.《Optimistic Concurrency Control》:https://15721.courses.cs.cmu.edu/spring2018/slides/04-occ.pdf)

11.《Base: An Acid Alternative》:https://queue.acm.org/detail.cfm?id=1394128

12.《Jepsen: CockroachDB beta-20160829》:https://jepsen.io/analyses/cockroachdb-beta-20160829

13.《Spanner: Google’s Globally-Distributed Database》:https://static.googleusercontent.com/media/research.google.com/en//archive/spanner-osdi2012.pdf

Apache ShardingSphere 如何实现分布式事务相关推荐

  1. ShardingSphere RAW JDBC 分布式事务 Narayana XA 代码示例

    ShardingSphere RAW JDBC 分布式事务 Narayana XA 代码示例 项目工程在:transaction-2pc-narayana-xa-raw-jdbc-example 代码 ...

  2. ShardingSphere RAW JDBC 分布式事务XA 代码示例

    ShardingSphere RAW JDBC 分布式事务XA 代码示例 项目工程在:transaction-2pc-xa-raw-jdbc-example 代码简介     基于ShardingSp ...

  3. Apache RocketMQ 正式开源分布式事务消息

    摘要: 近日,Apache RocketMQ 社区正式发布4.3版本.此次发布不仅包括提升性能,减少内存使用等原有特性增强,还修复了部分社区提出的若干问题,更重要的是该版本开源了社区最为关心的分布式事 ...

  4. 消息中间件学习总结(15)——Apache RocketMQ 正式开源分布式事务消息

    近日,Apache RocketMQ 社区正式发布4.3版本.此次发布不仅包括提升性能,减少内存使用等原有特性增强,还修复了部分社区提出的若干问题,更重要的是该版本开源了社区最为关心的分布式事务消息, ...

  5. 京东数科首次公开:强一致、高性能分布式事务中间件JDTX

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 作者 | 张亮 来源 | http://1t.click/aJPE 在分布式数据库.云原生数 ...

  6. 首次公开:京东数科强一致、高性能分布式事务中间件 JDTX

    来源:https://www.infoq.cn/article/BAXzcfjRTcgmKisa7JHm 在分布式数据库.云原生数据库.NewSQL 等名词在数据库领域层出不穷的当今,变革--在这个相 ...

  7. 分布式事务中间件你知道哪些?

    在分布式数据库.云原生数据库.NewSQL 等名词在数据库领域层出不穷的当今,变革--在这个相对稳定的领域已愈加不可避免.相比于完全革新,渐进式增强的方案在拥有厚重沉淀的行业则更受青睐. 同所有分布式 ...

  8. 【元宵节快乐】Apache ShardingSphere 企业行|走进陌陌

    2022 年 1 月,Apache ShardingSphere 核心技术团队来到陌陌研发中心,与陌陌的技术同学就中间件技术展开了深度交流和探讨. 作为一款基于地理位置的移动社交应用,用户可以在陌陌平 ...

  9. 深度剖析Apache Shardingsphere对分布式事务的支持

    Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 JDBC.Proxy 和 Sidecar(规划中)这 3 款相互独立,却又能够混合部署配合使用的产 ...

最新文章

  1. idea java编译报错_intellij-idea,java_idea 编译报错,intellij-idea,java - phpStudy
  2. byte转换int时为何与0xff进行与运算
  3. WebRTC / Jitsi / 使用 jitsi 官方源安装内网演示环境过程
  4. power designer 连接数据库提示“connection test failed”
  5. intelij不识别java文件
  6. linux分区后盘符找不到,为什么我的磁盘不见了,怎么找回来啊?
  7. python tkinter button_更改Python中Tkinter Button的命令方法
  8. sapi cli php mac,make: *** [sapi/cli/php] Error 1 解决办法
  9. 铜川市2021年高考成绩查询,2021年铜川高考各高中成绩排名查询,铜川高考成绩公布榜单...
  10. 当区块链遇到零知识证明 1
  11. Spring的cache缓存介绍
  12. 计算机网络章末总结,计算机网络 (前两章总结)
  13. Asp.Net Core Mvc上Json序列化首字母大小写的问题
  14. 基于麻雀算法改进的随机森林分类算法 - 附代码
  15. 英语口语笔记B1-Unit04.家居生活-02-Buying household products
  16. LCD1602液晶显示屏
  17. JDBC Connection [com.mysql.jdbc.Connection@2bbf4094] will not be managed by Spring 的一个可能错误
  18. 参赛【GGJ2022】回顾,作品--双生共合
  19. Mac book air在浏览器中显示flash过期问题
  20. 计算时区函数gmt2local(time_t t)

热门文章

  1. 麟卓卓懿:以非虚拟化技术助力Linux应用生态建设
  2. 学计算机河北科技华北理工,河北科技大学和华北理工大学全面对比
  3. 编程专用字体-JetBrains-Mono
  4. 宏定义之闰年判断C/C++版
  5. css通过计算得出width
  6. ExoPlayer添加滤镜功能
  7. Linux的uvc的摄像头驱动,[OpenWrt Wiki] Linux下的摄像头驱动UVC
  8. 为什么二维码营销可以火起来吗?
  9. a8 内存 华硕k550d_2019年华硕k550d怎么样-精选word文档 (2页)
  10. 942518-29-8,(S)-2-Amino-4-azido-butanoic acid HCl,L-叠氮高苏氨酸(AHA)是蛋氨酸的氨基酸类似物