9.2 RootServer实现机制

RootServer是OceanBase集群对外的窗口,客户端通过RootServer获取集群中其他模块的信息。RootServer实现的功能包括:

●管理集群中的所有ChunkServer,处理ChunkServer上下线;

●管理集群中的UpdateServer,实现UpdateServer选主;

●管理集群中子表数据分布,发起子表复制、迁移以及合并等操作;

●与ChunkServer保持心跳,接受ChunkServer汇报,处理子表分裂;

●接受UpdateServer汇报的大版本冻结消息,通知ChunkServer执行定期合并;

●实现主备RootServer,数据强同步,支持主RootServer宕机自动切换。

9.2.1 数据结构

RootServer的中心数据结构为一张存储了子表数据分布的有序表格,称为RootTable。每个子表存储的信息包括:子表主键范围、子表各个副本所在ChunkServer的编号、子表各个副本的数据行数、占用的磁盘空间、CRC校验值以及基线数据版本。

RootTable是一个读多写少的数据结构,除了ChunkServer汇报、RootServer发起子表复制、迁移以及合并等操作需要修改RootTable外,其他操作都只需要从RootTable中读取某个子表所在的ChunkServer。因此,OceanBase设计时考虑以写时复制的方式实现该结构,另外,考虑到RootTable修改特别少,实现时没有采用支持写时复制的B+树或者跳跃表(Skip List),而是采用相对更加简单的有序数组,以减少工作量。

往RootTable增加子表信息的操作步骤如下:

1)拷贝当前服务的RootTable为新的RootTable;

2)将子表信息追加到新的RootTable,并对新的RootTable重新排序;

3)原子地修改指针使得当前服务的RootTable指向新的RootTable。

ChunkServer一次汇报一批子表(默认一批包含1024个),如果每个子表修改都需要拷贝整个RootTable并重新排序,性能上显然无法接受。RootServer实现时做了一些优化:拷贝当前服务的RootTable为新的RootTable后,将ChunkServer汇报的一批子表一次性追加到新的RootTable中并重新排序,最后再原子地切换当前服务的RootTable为新的RootTable。采用批处理优化后,RootTable的性能基本满足需求,OceanBase单个集群支持的子表个数最大达到几百万个。当然,这种实现方式并不优雅,我们后续将改造RootTable的实现方式。

ChunkServer汇报的子表信息可能和RootTable中记录的不同,比如发生了子表分裂。此时,RootServer需要根据汇报的tablet信息更新RootTable。

如图9-2所示,假设原来的RootTable包含四个子表:r1(min,10]、r2(10,100]、r3(100,1000]、r4(1000,max]、ChunkServer汇报的子表列表为:t1(10,50]、t2(50,100]、t3(100,1000],表示r2发生了tablet分裂,那么,RootServer会将RootTable修改为:r1(min,10]、r2(10,50]、r3(50,100]、r4(100,1000]、r5(1000,max]。

9.2 RootServer实现机制 - 图1

图 9-2 RootTable修改

RootServer中还有一个管理所有ChunkServer信息的数组,称为ChunkServer-Manager。数组中的每个元素代表一台ChunkServer,存储的信息包括:机器状态(已下线、正在服务、正在汇报、汇报完成,等等)、启动后注册时间、上次心跳时间、磁盘相关信息、负载均衡相关信息。OceanBase刚上线时依据每台ChunkServer磁盘占用信息执行负载均衡,目的是为了尽可能确保每台ChunkServer占用差不多的磁盘空间。上线运行一段时间后发现这种方式效果并不好,目前的方式为按照每个表格的子表个数执行负载均衡,目的是尽可能保证对于每个表格、每台ChunkServer上的子表个数大致相同。