本文作者:泽寰 ,OceanBase 分布式事务工程师
本节为源码解读的第十篇,本文书接前文——在《 OceanBase 源码解读(五)事务的一生》中对事务的外部接口进行了介绍,本节讲一些事务模块内部细节。
概述
既然是分布式数据库,分布式事务的能力是必不可少的。关于事务的特性,总结如下:
1)两阶段提交(下文简称 2PC )协议,极致优化;
2)全局快照;
3)外部一致性;
4)巧妙解决:分布式事务领域的读半提交、事务提交与查询并发产生的读原子性问题;
关于上述问题4,国内数据库多位专家在不同的场合都做了描述,且给出了解决方案,并且质疑 OceanBase 关于这块的能力。实际情况是:OB1.4 就已经认识到并且解决了这两个问题,如何解决,这里卖个关子,大家一起来 review 代码(我们内部的说法是:假如这两个问题你能清晰地描述出相关实现细节,你对 OceanBase 事务的代码基本是已经比较清楚了),加油。
接下来本文从事务执行流程、快照管理、事务提交、并发控制、全局时间戳等几个方面进行代码走读。
执行流程
不论显式还是隐式事务,对事务层而言,接口是统一的,具体包括:
具体接口,这篇文章——《OceanBase 源码解读(五)事务的一生》已经给了详细的说明,本文不再赘述。
快照管理
OceanBase 的快照概括起来主要分为两种:语句级别快照、事务级别快照。RC 隔离级别下,主要使用语句级别快照,语句开启过程中生成;RR 和 Serializable 隔离级别下,使用事务级别快照,事务开启过程中生成。关于快照的生成,代码接口:
理论上来讲,语句或事务的快照都可以获取 gts,但出于对性能的考虑,有些场景调用 get_publish_version,有些场景 get_local_trans_version 等等。
事务提交
不论单机还是多机场景,只要是多分区事务 OceanBase 均称为分布式事务。为了性能的考虑,单机多分区事务和单分区事务的事务提交,做了一定的优化。单机多分区事务提交,本质上依然是两阶段,而单分区事务完全走一阶段提交。
整体而言,事务提交的整体逻辑主要集中在以下文件:
分布式事务提交整体流程,核心调用路径:
并发控制
OceanBase 并发控制基于 Mvcc+ 行锁的机制来实现,具体而言,读不加锁,读写不相互阻塞、写写并发通过行锁互斥来保证。实现上,代码相对比较集中,主要包括如下文件:
全局时间戳服务
OceanBase 通过租户级别内部表,以其 leader 所在的机器的时钟作为本租户的全局时钟,从而实现了租户内部全局时间戳服务 GTS(没有跨租户的事务,因此不要所有租户的全局时间戳服务需求)。
有了 GTS ,分布式场景下的读半提交问题可以迎刃而解。在读已提交隔离级别下,每一个语句可以在执行前通过 GTS 服务来获取读取版本号来避免该异常。然而,对于单机事务的读取操作,为了进一步提升系统性能,我们可以不用通过 GTS 服务端来获取读取版本号,具体的解决方案,大家可以仔细 review 代码。
关于 GTS 的相关实现,代码比较集中,具体如下:
(未完待续)
附录:前九篇可参考:
1、OceanBase 数据库源码解读(一)引言
2、OceanBase 数据库源码解读(二)目录结构
3、OceanBase 源码解读(三)SQL 的一生
4、OceanBase 源码解读(四)分区的一生
5、OceanBase 源码解读(五)事务的一生
6、OceanBase 源码解读(六)租户的一生
7、OceanBase源码解读(七)带你看透虚拟表
8、OceanBase源码解读(八)OB高性能执行引擎
9、OceanBase源码解读(九)tableAPI和OB多模型
联系我们
欢迎广大 OceanBase 爱好者、用户和客户随时与我们联系、反馈,方式如下:
社区版官网论坛
社区版项目网站提 Issue
钉钉群:33254054