OceanBase调研

介绍

OceanBase 在支付宝其实已经服务多年,是一款非常有实力的国产分布式数据库,主打高性能、高可用、低成本和线性扩展。尤其在金融领域有丰富的经验。现在也已经开源。本文基于一些公开资料的学习给自己做个总结

基本架构

image.png

整体是一个share-nothing架构,具备良好的并行和扩展性。下面介绍下其核心的组件:

  • 集群:一个集群下可以有属于多个可用区的节点共同组成
  • region: 物理地域,可以是一个城市或者地域
  • 可用区: 一个region由多个zone组成,一个可用区下可以有多个节点
  • ob server节点:一个ob server实例相当于一个节点,一个节点归属于一个可用区。一个ob server是一台物理机。
  • 租户:租户可以理解为是隔离的数据库,类似Oracle中一个独立的库。observer会父子创建租户的独立资源池,隔离CPU和内存资源使用。这个对于一些优先级划分是很有帮助的。
  • obproxy: 无状态的数据库代理,负责分发SQL请求、连接管理、数据路由、兼容MySQL和Oracle协议
  • 分区:图上的P就是一个分区。ob内部分区的类型有全能型(F)、日志型(L)、加密投票型(E)和只读副本型®。其中只读副本不构成paxos成员组。不同副本能力上存在差异。这个有点类似oracle不同的文件类型,数据文件、日志文件,可以参照这么理解。
  • 副本:数据是多份存储在分区内,有主副本和从副本
  • RootService: 主要负责资源管理、分区负载均衡管理、schema管理、集群自举、分区leader选举等,运行在集群的zone内部的某一台ob server上

一般部署模式

image.png

存储层

image.png
整体上是基于LSM设计的存储结构,不过oceanbase有一些自己的优化,达到了总体上低成本、易使用、高性能、高可靠的效果。OB内存里面同时有hash表和B+树 应对点查和范围查询的场景。虽然基于LSM,但是oceanbase本质还是一个行存数据库,基本数据块中存储的是row的信息。

优化点

宏块与微块(性能)

oceanbase引入宏块,将数据文件拆分成较粗粒度,没有变更的宏块在compaction的时候不进行完整读取,降低compaction的代价。一个SSTable实际上就是多个宏块的集合。微块是文件读IO最小单位,包含若干数据行,多个微块又构成了一个宏块。微块构建分flat和encoding两种偶见模式。内存里面的是增量数据,磁盘上的是基线数据。encoding只针对基线数据。压缩编码在微块粒度上进行。经历填充行->编码->通用压缩->加密。OB支持的加密算法为zlib、snappy、lz4和zstd。

image.png

多级缓存(性能)

LSM设计一般都有块缓存,ob 自己设计了一套多级缓存的框架,主要包含:

  • 行缓存,减少了读放大,对TP事物支持更好。
  • log cache:缓存redo log
  • location cache:缓存数据副本所在的位置
  • schema cache:缓存schema信息

分层转储(性能)

实际上理解也比较简单,就是在内存层面支持多个frozen memtable;在disk L0层支持多个mini sstable。避免形成一个过大的memtable
image.png

行列混合编码(成本)

OB通过自研编码压缩算法,数据存储压缩率比传统数据库有10+倍提升。原理上定长部分用按列编码,存储在微块的列存区,变长部分按行存储,存储在变长区。读取微块一行时,可以只对一行数据进行解码。3.2版本后,encoding支持了avx2的向量化执行。

轮转合并(可靠性)

把正常服务和合并时间错开,避免合并影响用户正常请求

数据校验(可靠性)

ob具备全链路的数据校验,在合并时也会比较多副本以及主表索引表比对来保证数据准确性

范围删除标记(性能)

LSM对于大量删除不友好,因为本质也是对所有行做删除标记,无法避免合并时的完整扫描。ob提供了一个范围删除标记,通过特殊的转储合并提前回收这些删除行来加速查询性能。

隐藏主键

无主键表有隐藏主键,所有数据表都是索引聚簇表。插入会判断PK冲突,PK冲突频率高的会异步构建bloom filter

非全列更新信息

更新操作只记录PK和更新列的新值,加速compaction效率

partition group (PG)

这个概念是为了优化性能而产生的。OB提供语法将相同分区键、分区规则的表定义成一个PG,OB保证听一个PG中的partition都是在一起的,那么一个PG下的事务会降级成单机事务,效率会比较高。
image.png

数据合并

OceanBase支持多种合并方式,比较灵活

  • 全量合并(需手动开启):类似marjor compaction,静态数据和内存数据全量合并会消耗大量IO和空间
  • 增量合并(默认):宏块和微块没修改都可以重用,在微块级增量及合并,减少合并代价
  • 渐进合并:主要是为了DDL变更服务,DDL变更造成的数据合并分散到多次每日合并去做
  • 并行合并:分区内、分区间并行合并
  • 轮转合并:低峰时间进行合并

计算层

基本架构流程

计算层主要是SQL引擎的实现,下图演示了SQL引擎在整个体系中的位置以及一个SQL执行的过程。
image.png

SQL语句并行执行流程

用户连接的observer称之为QC(query coordinator),执行步骤如下:

  1. QC预约足够的线程资源
  2. QC将需要并行的计划拆成多个子计划,即DFO(data flow operation)。每个DFO包含若干个执串行执行的算子。例如,一个DFO里包含了扫描分区、聚集和发送算子的任务,另外一个DFO包含了收集、聚集算子等任务
  3. QC按照一定的逻辑顺序将DFO调度到合适的OBServer上执行,OBServer上会临时启动一个辅助协调者SQC(sub query coordinator),SQC负责在所在OBServer上位各个DFO申请执行资源、构造执行上下文等环境等,然后启动DFO在各个OBServer上进行并行执行
  4. 当各个DFO都执行完毕,QC会串行执行剩余部分的计算。例如一个并行的COUNT算法最终需要QC将各个机器上的计算结果做一个SUM运算
  5. QC所在线程将结果返回给哭护短

image.png

功能特性

兼容模式

ob支持MySQL和Oracle的兼容模式,让原oracle和mysql的用户迁移到ob的过程变得十分容易和自然,这对ob在国内的推广具有重要意义。

表组

这个概念是为了保证分布式环境下做join时的data locality优化。相同分区方式的表放在一个机器上,这样做join的时候可以避免跨机分布式事务,有更好的性能。
image.png

全局索引

ob中全局索引有如下特点:

  • 索引表分区的方式是独立的
  • 全局分区索引存在索引键映射到不同分区的情况

image.png

分布式数据中实现全局索引存在一些挑战,主要是:

  • 保证主表数据和索引数据的跨机器同步更新(一致性):这个可以基于paxos协议和2PC去完成
  • 索引数据和主表数据分跨机器访问时的效率问题(性能): ob通过改进的2PC来解决
  • 分布式数据库中全局(跨多台机器)的读写一致性问题:ob提供全局一致性快照可以解。

全局一致性快照与全局时间戳

全局一致性快照实现的关键是全局一致性版本号的使用。一般是利用精确的物理时钟或者软件的全局时间戳服务(GTS)。oceanbase采用的GTS服务架构如下,设计的特点在于GTS也是和租户去对应的,这样GTS本身的扩展性也是会比较好,由于GTS引发的故障scope也只会限定在租户级。此外GTS也支持高可用,默认三副本。
image.png

数据闪回

本质上是有数据前镜像,ob支持在oracle、mysql模式上采用闪回sql访问被误删的数据。例如:

1
2
3
4
5
6
### oracle模式,通过 TIMESTAMP 指定的历史时间并闪回查询一张单表在该历史时间中的状态的数据
obclient> SELECT * FROM tbl1 as of timestamp TO_TIMESTAMP('2020-08-13 16:20:00','yyyy-mm-dd hh24:mi:ss');

##mysql 模式 通过 AS OF SNAPSHOT 指定历史时间并闪回查询单表在该历史时间点的状态的数据的示例如下:
obclient> SELECT * FROM table1 AS OF SNAPSHOT 1582807800000000;

自动负载均衡

均衡组维度均衡

ob定义了几种均衡组。不同均衡组定义了特定的一些分区。在均衡组维度对分区进行均衡从而保证各个均衡组内的分区均衡。均衡的维度是在整个zone内。

Primary zone内的leader分区均衡

存放leader主分区的zone称之为primary zone,这个可以由ob去定义,定义好了primary zone的个数,ob会把leader分区均衡到这些zone的上。下面是只设置一个primary zone的例子
image.png

自动死锁检测

OB实现的是一种基于优先级的多出度分布式死锁检测方案(LCL-Lock chain length),这种检测方式属于边跟踪算法的模式。优先级最低的事务指的是冲突事务中开启最晚的事务。一个事务同时等待多个事务的单向依赖的有向边称为多出度。传统采用路径推动算法(path-pushing algorithm)的死锁检测有多杀及误杀事务的问题。LCL引入一个令牌保证只有最大令牌值的节点去探测到死锁并进行kill,避免误杀和多杀。

tips: 死锁检测是个关注蛮多的领域,EDGAR KNAPP把分布式死锁检测算法分为了四类。有兴趣可以了解下:

  • Path-Pushing Algorithms(路径推动算法)
  • Edge-Chasing Algorithms(边追踪算法)
  • Diffusing Computations(扩散计算)
  • Global State Detection(全局状态检测)

周边生态

应用场景

  • OB比较关注严苛的TP场景,重视locality,比如和TIDB比较的话,每个observer包含完整的SQL ENGINE、memory table、sstable等核心组件,避免跨网络交互。
  • 事务提交不需要所有节点参与,有只读副本。事务提交保证不丢即可,避免过多节点参与多数派选举导致的延迟问题。

感悟:企业规模不同阶段用不同数据库即可。数据量小,用单机数据库就最好。

参考资料