从全局来看,OceanBase的存储引擎是分布在各个OBServer上的,即每台OBServer负责管理全局数据中的一部分,OBServer上发生的数据修改通过日志复制到具有相同副本的其他OBServer上。因此从局部来看,每台OBServer上也拥有一个完整的存储引擎,其总体架构如图4.1所示。
图4.1 存储引擎总体架构
OceanBase的存储引擎采用了基于LSM-Tree的架构,把基线数据(SSTable)和增量数据(MemTable)分别保存在持久化存储(SSD或者磁盘)和内存中。OBServer中对数据的修改都作为增量数据写入内存中,因此数据的增、删、改全都是内存操作,使得操作性能很好。当然仅将数据修改放在内存中是无法达到持久化的,因此OceanBase结合集群中的多副本以及事务日志共同保证了数据修改的持久化。需要读取数据时,由于内存中只有增量修改,要获得完整的数据还需要从基线数据中拿到目标数据的基础版本,并在其上加上增量之后才能得到该数据的最新版本。对于某个数据(元组),内存中会存有该数据被多次修改形成的多个增量数据,这些增量数据配合基线数据自然而然地形成了该数据的多个版本,可以用来支撑系统中的多版本并发控制(Multi-Version Concurrency Control,MVCC)。
为了提高对数据的访问速度,OceanBase存储引擎构建了两种缓存:行缓存(Row Cache)和块缓存(Block Cache)。基线数据的I/O单位是块(Block),存储引擎采用块缓存提高I/O利用率。对于行的操作会利用块缓存中的块和增量数据构造出“行”形式的数据,为了避免重复施行这种构造,构造形成的行会被放在行缓存中重复使用。除缓存的数据形式不同之外,两种缓存的使用场景也有所不同。OLTP业务大部分操作为小查询,存储引擎优先使用行缓存来回答查询,从而避免了解析整个数据块的开销,达到了接近内存数据库的性能。而对于涉及数据量很大的OLAP业务,则优先使用块缓存。
当增量数据达到一定规模的时候,存储引擎会触发增量数据和基线数据的合并,把增量数据持久化为基线数据的一部分。同时每天晚上的空闲时刻,系统也会启动每日合并。另外,由于基线是只读数据,而且内部采用连续存储的方式,存储引擎可以根据不同特点的数据采用不同的压缩算法,既能做到高压缩比,又不影响查询性能。