OceanBase调研
介绍
OceanBase 在支付宝其实已经服务多年,是一款非常有实力的国产分布式数据库,主打高性能、高可用、低成本和线性扩展。尤其在金融领域有丰富的经验。现在也已经开源。本文基于一些公开资料的学习给自己做个总结
基本架构
整体是一个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上
一般部署模式
存储层
整体上是基于LSM设计的存储结构,不过oceanbase有一些自己的优化,达到了总体上低成本、易使用、高性能、高可靠的效果。OB内存里面同时有hash表和B+树 应对点查和范围查询的场景。虽然基于LSM,但是oceanbase本质还是一个行存数据库,基本数据块中存储的是row的信息。
优化点
宏块与微块(性能)
oceanbase引入宏块,将数据文件拆分成较粗粒度,没有变更的宏块在compaction的时候不进行完整读取,降低compaction的代价。一个SSTable实际上就是多个宏块的集合。微块是文件读IO最小单位,包含若干数据行,多个微块又构成了一个宏块。微块构建分flat和encoding两种偶见模式。内存里面的是增量数据,磁盘上的是基线数据。encoding只针对基线数据。压缩编码在微块粒度上进行。经历填充行->编码->通用压缩->加密。OB支持的加密算法为zlib、snappy、lz4和zstd。
多级缓存(性能)
LSM设计一般都有块缓存,ob 自己设计了一套多级缓存的框架,主要包含:
- 行缓存,减少了读放大,对TP事物支持更好。
- log cache:缓存redo log
- location cache:缓存数据副本所在的位置
- schema cache:缓存schema信息
分层转储(性能)
实际上理解也比较简单,就是在内存层面支持多个frozen memtable;在disk L0层支持多个mini sstable。避免形成一个过大的memtable
行列混合编码(成本)
OB通过自研编码压缩算法,数据存储压缩率比传统数据库有10+倍提升。原理上定长部分用按列编码,存储在微块的列存区,变长部分按行存储,存储在变长区。读取微块一行时,可以只对一行数据进行解码。3.2版本后,encoding支持了avx2的向量化执行。
轮转合并(可靠性)
把正常服务和合并时间错开,避免合并影响用户正常请求
数据校验(可靠性)
ob具备全链路的数据校验,在合并时也会比较多副本以及主表索引表比对来保证数据准确性
范围删除标记(性能)
LSM对于大量删除不友好,因为本质也是对所有行做删除标记,无法避免合并时的完整扫描。ob提供了一个范围删除标记,通过特殊的转储合并提前回收这些删除行来加速查询性能。
隐藏主键
无主键表有隐藏主键,所有数据表都是索引聚簇表。插入会判断PK冲突,PK冲突频率高的会异步构建bloom filter
非全列更新信息
更新操作只记录PK和更新列的新值,加速compaction效率
partition group (PG)
这个概念是为了优化性能而产生的。OB提供语法将相同分区键、分区规则的表定义成一个PG,OB保证听一个PG中的partition都是在一起的,那么一个PG下的事务会降级成单机事务,效率会比较高。
数据合并
OceanBase支持多种合并方式,比较灵活
- 全量合并(需手动开启):类似marjor compaction,静态数据和内存数据全量合并会消耗大量IO和空间
- 增量合并(默认):宏块和微块没修改都可以重用,在微块级增量及合并,减少合并代价
- 渐进合并:主要是为了DDL变更服务,DDL变更造成的数据合并分散到多次每日合并去做
- 并行合并:分区内、分区间并行合并
- 轮转合并:低峰时间进行合并
计算层
基本架构流程
计算层主要是SQL引擎的实现,下图演示了SQL引擎在整个体系中的位置以及一个SQL执行的过程。
SQL语句并行执行流程
用户连接的observer称之为QC(query coordinator),执行步骤如下:
- QC预约足够的线程资源
- QC将需要并行的计划拆成多个子计划,即DFO(data flow operation)。每个DFO包含若干个执串行执行的算子。例如,一个DFO里包含了扫描分区、聚集和发送算子的任务,另外一个DFO包含了收集、聚集算子等任务
- QC按照一定的逻辑顺序将DFO调度到合适的OBServer上执行,OBServer上会临时启动一个辅助协调者SQC(sub query coordinator),SQC负责在所在OBServer上位各个DFO申请执行资源、构造执行上下文等环境等,然后启动DFO在各个OBServer上进行并行执行
- 当各个DFO都执行完毕,QC会串行执行剩余部分的计算。例如一个并行的COUNT算法最终需要QC将各个机器上的计算结果做一个SUM运算
- QC所在线程将结果返回给哭护短
功能特性
兼容模式
ob支持MySQL和Oracle的兼容模式,让原oracle和mysql的用户迁移到ob的过程变得十分容易和自然,这对ob在国内的推广具有重要意义。
表组
这个概念是为了保证分布式环境下做join时的data locality优化。相同分区方式的表放在一个机器上,这样做join的时候可以避免跨机分布式事务,有更好的性能。
全局索引
ob中全局索引有如下特点:
- 索引表分区的方式是独立的
- 全局分区索引存在索引键映射到不同分区的情况
分布式数据中实现全局索引存在一些挑战,主要是:
- 保证主表数据和索引数据的跨机器同步更新(一致性):这个可以基于paxos协议和2PC去完成
- 索引数据和主表数据分跨机器访问时的效率问题(性能): ob通过改进的2PC来解决
- 分布式数据库中全局(跨多台机器)的读写一致性问题:ob提供全局一致性快照可以解。
全局一致性快照与全局时间戳
全局一致性快照实现的关键是全局一致性版本号的使用。一般是利用精确的物理时钟或者软件的全局时间戳服务(GTS)。oceanbase采用的GTS服务架构如下,设计的特点在于GTS也是和租户去对应的,这样GTS本身的扩展性也是会比较好,由于GTS引发的故障scope也只会限定在租户级。此外GTS也支持高可用,默认三副本。
数据闪回
本质上是有数据前镜像,ob支持在oracle、mysql模式上采用闪回sql访问被误删的数据。例如:
1 | ### oracle模式,通过 TIMESTAMP 指定的历史时间并闪回查询一张单表在该历史时间中的状态的数据 |
自动负载均衡
均衡组维度均衡
ob定义了几种均衡组。不同均衡组定义了特定的一些分区。在均衡组维度对分区进行均衡从而保证各个均衡组内的分区均衡。均衡的维度是在整个zone内。
Primary zone内的leader分区均衡
存放leader主分区的zone称之为primary zone,这个可以由ob去定义,定义好了primary zone的个数,ob会把leader分区均衡到这些zone的上。下面是只设置一个primary zone的例子
自动死锁检测
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等核心组件,避免跨网络交互。
- 事务提交不需要所有节点参与,有只读副本。事务提交保证不丢即可,避免过多节点参与多数派选举导致的延迟问题。
感悟:企业规模不同阶段用不同数据库即可。数据量小,用单机数据库就最好。