功能一:可串行化隔离级别
OceanBase 2.2 版本在之前 MySQL 兼容性模式的基础上推出了兼容 Oracle 的模式。事务处理能力是 Oracle 兼容性模式的重要组成部分。Oracle 事务引擎最有特点的功能是基于多版本控制的事务隔离能力,支持读已提交(Read Committed)和可串行化(Serializable)两种隔离级别。Oracle 两种隔离级别均支持读写分离能力,修改操作不会影响读取的进行,读取操作也不会阻塞修改。
OceanBase 2.2 版本的 Oracle 兼容模式目标是提供给用户方便的移植应用的能力。OceanBase 事务引擎完全兼容 Oracle 的Read Committed和Serializable隔离级别。OceanBase 的事务处理采用的也是多版本并发控制的方案,DML 语句的修改不是在数据项上直接生效,而是以一个新版本的形式写入,同时保留旧版本的数据。
OceanBase 中的每一个事务有两种版本号,一个是读取使用的版本号,另一个是提交版本号。读取使用的版本号叫做“读版本号”或者“快照版本号”,对于读取的每一行数据,即使行上有新的修改,读取操作依然要找到快照版本号所对应的数据项。事务的提交版本号是在事务提交时产生,本事务的所有修改数据都会被标记上这个“提交版本号”。
Read Committed与Serializable两种隔离级别的不同在于“读版本号”的生成逻辑。Read Committed 为了实现读到已经提交的数据,事务内每条语句会取当前系统的最新版本号,保证读取操作不会遗漏读取所在事务开启后才提交的其他事务所做的修改。Serializable隔离级别是在事务开始时获取了”读版本号“后,整个事务不会再变化,保证了整个事务都会见到数据库的同一个快照状态。
举个例子来说明两者的特性。下图演示在 Read Committed 隔离级别下,事务内可以见到别的事务修改完成的数据。
下图演示在Serializable隔离级别下,事务内不能见到别的事务修改完成的数据。
应用如何选择 Read Committed 还是 Serializable 隔离级别没有一招鲜的策略,需要从实际需要出发。通常来说,Read Committed 可以满足大部分应用场景的需求。同时,Serializable隔离级别为了支持事务级别的快照能力,可能会引发更大概率事务调度异常,最终导致并发的事务执行无法满足可串行化隔离级别,出现回滚。下面的例子描述了一种无法串行化的报错。
功能二:实时一致的复制表
OceanBase 的分布式架构从本质上决定了数据被分散在不同的机器上分别服务,SQL 语句执行时会根据所操作数据的位置生成最优的执行计划,或在一台机器或在多台机器运行 SQL 的执行计划。
虽然 SQL 引擎会根据最优的策略来优化执行的开销和执行的时间,但是涉及多台机器数据的操作时,跨机器之间的数据传输很多时候不可避免。例如很多业务中存储关键信息的配置表,还有金融业务中存储汇率信息的表。
这类表格内的数据被频繁访问,通过网络被反复的传输到各台机器上,带来的开销有时很大,而这种开销可以通过“复制表”功能来优化。复制表将需要被频繁访问的数据复制到集群的每一台机器上,反复的操作不需要再跨机传输数据。
TPC-C 测试模型中有一张商品(ITEM)表,这张表的内容是测试所模拟的销售公司所有售卖的商品信息,包含了商品的名字、价格等信息。“订单创建”事务执行中需要请求这张表内的数据来确定订单的价格信息,这样的商品表也是复制表可以优化的典型场景。
将数据复制到多机带来的最大挑战是对于数据的修改要在所有机器上实时生效,否则一部分机器读到新的数据另一部分读到旧的数据,这一定是不满足用户需求的功能。OceanBase 使用特殊的广播协议保证复制表的副本一致性,当复制表发生修改时,所有的副本会同时修改。并且,只有在所有机器上的副本都修改成功时,修改操作才会生效。
在分布式系统中,另一个棘手的问题又会出现,如果复制表修改的过程中有机器出现故障,故障机器上的复制表的副本无法修改,那么复制表就再也不能改了吗?如果不解决这个问题,复制表在出现机器故障时就会拖累用户的操作。
OceanBase 采用了租约机制来解决这个难题。每台机器上有效的复制表副本都会获得租约,当复制表修改时,修改要同步到所有有租约的副本。如果出现机器故障,故障机器上的复制表副本的租约会失效,失效的副本不会被同步新的修改,所以不会阻塞复制表后续的修改操作。失效的副本同时会拒绝读取操作,保证不会读到旧的数据。当失效副本恢复后,可以追赶遗漏的数据,等其追赶到最新状态后会被重新授予租约。
功能三:指定快照版本查询
OceanBase 事务引擎的多版本并发控制机制是通过修改操作产生新的数据版本来实现,这个机制除了可以解决事务并发控制的需求,还能够支持其他很多功能,比如指定快照版本查询的能力可以用于查看历史数据,兼容 Oracle 的 Flashback Query 功能。
用户可以在 SELECT 语句中使用 AS OF 关键字来指定需要读取的历史版本,支持使用 SCN和 TIMESTAMP 两种方式。使用 SCN 指定事务提交版本号,使用 TIMESTAMP 指定一个具体的时间戳。而 OceanBase 允许用户回溯的历史时间通过 UNDO_RETENTION 变量来指定,OceanBase 会保留 UNDO_RETENTION 时间内的所有历史版本。
下面是一个使用方式的样例。
指定快照版本查询的功能在很多场景都有用,OceanBase 的数据导出工具内就使用了此功能来提供一致的快照导出能力。导出工具会在开始时确定导出事务版本号,在之后读取数据时均使用SELECT AS OF语句指定版本号读取,那么所有导出的数据都是数据库内的一个快照版本状态。




