子表分裂由ChunkServer在定期合并过程中执行,由于每个子表包含多个副本,且分布在多台ChunkServer上,如何确保多个副本之间的分裂点保持一致成为问题的关键。OcanBase采用了一种比较直接的做法:每台ChunkServer使用相同的分裂规则。
由于每个子表的不同副本之间的基线数据完全一致,且定期合并过程中冻结的增量数据也完全相同,只要分裂规则一致,分裂后的子表主键范围也保证相同。
OcanBase曾经有一个线上版本的分裂规则如下:只要定期合并过程中产生的数据量超过256MB,就生成一个新的子表。假设定期合并产生的数据量为257MB,那么最后将分裂为两个子表,其中,前一个子表(记为r1)的数据量为256MB,后一个子表(记为r2)的数据量为1MB。接着,r1接受新的修改,数据量很快又超过256MB,于是,又分裂为两个子表。系统运行一段时间后,充斥着大量数据量很少的子表。
为了解决分裂产生小子表的问题,需要确保分裂以后的每个子表数据量大致相同。OceanBase对每个子表记录了两个元数据:数据行数row_count以及子表大小(occupy_size)。根据这两个值,可以计算出每行数据的平均大小,即:occupy_size/row count。
根据数据行平均大小,可以计算出分裂后的子表行数,从而得到分裂点。子表合并相对更加麻烦,步骤如下:
1)合并准备:RootServer选择若干个主键范围连续的小子表;
2)子表迁移:将待合并的若干个小子表迁移到相同的ChunkServer机器;
3)子表合并:往ChunkServer机器发送子表合并命令,生成合并后的子表范围。
【例】某OceanBase集群中有3台ChunkServer:ChunkServerl(包含子表A1、A3),ChunkServer2(包含子表A2、A3),ChunkServer3(包含子表A1、A2),其中,Al和A2分别为10MB,A3为256MB。RootServer 扫描RootTable后发现Al和A2满足子表合并条件,首先发起子表迁移,假设将Al迁移到ChunkServer2。使得Al和A2在相同的ChunkServer上,接着分别向ChunkServer2和ChunkServer3发起子表合并命令。
子表合并完成以后,子表分布情况为:ChunkServerl(包含子表A3),
ChunkServer2(包含子表A4(A1,A2).A3),ChunkServer3(包含子表A4(A1,A2)),其中,A4是子表Al和A2合并后的结果。
每个子表包含多个副本,只要某一个副本合并成功,OceanBase就认为子表合并成功,其他合并失败的子表将通过垃圾回收机制删除掉。