分区内并行创建索引

ywz888
发布于 2022-10-10 16:14
浏览
0收藏

介绍

OceanBase分区能按照某种规则自动地对数据表进行划分,每个分区存储表格的一部分数据。相对于分库分表方案,分区功能既能对用户比较透明,又具有良好的可扩展性。

在OceanBase中,针对分区表构建索引时,会对该表格的每个分区进行外部排序,构建相应的索引表,由于分区的数据量通常是GB,甚至是TB级别的,采用串行的外部排序构建索引容易达到瓶颈,因此,需要分区内并行构建索引的功能。

本文主要描述了OceanBase 分区内并行构建索引的方案,全文包括如下部分:

  • OceanBase分区和索引介绍
  • 现有构建索引方案的瓶颈分析
  • 分区内并行建索引优化方案

OceanBase分区和索引介绍

分区

OceanBase分区能够自动地按照用户定义的分区规则,将表格中的数据划分到相应的分区,并且分区能够分布在不同的服务器上,具有良好的可扩展性。目前OceanBase支持二级分区,用户可以根据需求,制定分区格式。

索引

OceanBase的数据存储格式为SSTable,SSTable中的数据是按照表格的主键升序组织的。索引表的存储格式也是SSTable,其按照索引表的主键升序存储。例如,有一张数据表test,包含列a b c d e,其中主键为a,那么,test的SSTable中的数据是按照列a的升序方式存储的;如果在数据表test上建立一个索引index,假设包含列c、b、a,那么,index的SSTable按照主键c、b、a的升序存储的。

在数据表建立索引之后,需要按照分区针对索引列排序,以便得到按索引列升序方式组织的SSTable,通常地,分区的数据量往往比较大,无法完全装入内存直接排序,此时,一般采用磁盘作为辅助存储空间,进行外部排序,来构建索引。

现有构建索引方案的瓶颈分析

在数据量超过一定大小时,现有构建索引的方案采用单线程外部排序的方式来构建索引,先简单地介绍下这个流程:

假设允许使用的内存的缓存数量为B,待排序的数据总量为N个缓存大小,整个排序过程如下:

  • 第一轮:每次读B个缓存的数据量,排序,然后写入磁盘,形成一个分片,重复该过程,直到所有的数据都排序过
  • 第二轮到结束:合并上一轮的B个分片,形成一个更大的分片并写入磁盘,重复该过程,直到最后只有一个全局排序的分片

在分区数据量较大时,上述单线程构建索引的方案容易出现瓶颈,以某业务的某个索引构建时间进行分析,每轮花费的时间如下:

  • 第一轮:3.6小时
  • 第二轮:0.75小时
  • 第三轮:0.63小时
  • 第四轮:0.65小时

以第一轮为例,其中排序的开销为3小时,其他的开销,如写盘,迭代行的开销总共为0.6小时,因此,排序为瓶颈所在,主要考虑外部排序的并行化。

分区内并行建索引方案

分区内并行建索引的本质是外部排序的并行化,本节首先描述了外部排序并行化的常见思路,为了方便,以如下例子来说明:

假设有一张表,其创建语句为

CREATE TABLE test (c1 int primary key, c2 int);


在其上建立一个索引

CREATE INDEX index_test on test(c2);

数据表test已经按照c1排好序,构建index_test时,则需要按照索引列c2排好序,并存储到SSTable中。

外部排序并行化的思路

外部排序的并行化一般有如下思路:

  • 思路一:并行局部排序后,单线程归并
  • 思路二:并行局部排序后,按照索引列范围划分数据,接着做一次并行局部排序
  • 思路三:先按照索引列范围划分数据,接着并行局部排序

目前采用思路一方案。

主要包含以下流程:

  • 数据划分:按照数据表的主键范围进行数据划分
  • 并行局部排序:每个线程对自己所属的数据进行局部排序
  • 归并局部排序结果:局部排序后的结果并不是全局有序的,需要按照索引列的排序规则归并成全局有序的结果

在数据划分阶段,先按照数据表的主键范围进行数据划分,由于数据表已经是按照主键排好序,因此,划分数据的开销很小。但是,划分的数据是按照数据表的主键列(图中的C1)排好序的,通常对于索引列(图中的C2)并不是排好序的,例如,上图中CPU0分到的索引列数据为19 1 5 3 13。

在并行局部排序阶段,每个线程针对划分的数据,对索引列进行排序,例如,CPU0划分到的索引列数据C2为19 1 5 3 13,按照索引列排好序后,数据为1 3 5 13 19。

由于并行局部排序后,得到的数据并不是全局有序的,因此,还需要对各路局部排序的结果进行归并,最终得到全局有序的数据。

思路一的优点是:

  • 数据划分可以做到均衡,每个线程局部排序的工作量大致相同

思路一的缺点是:

  • 归并局部排序结果阶段是单线程工作的,扩展性较弱

从时间分析来看,最后一轮单线程merge的时间大约占串行建索引整体时间的1/8左右,采用思路一能提升的空间还是比较可观的。

外部排序并行化的实现

在实现时,除了上述的并行外部排序的逻辑以外,还需要考虑以下问题:

  • 如何控制局部排序和归并排序任务的执行顺序?
  • 外排过程中的临时数据如何存储?

如何控制局部排序和归并排序任务的执行顺序?

从思路一的执行过程看出,局部排序和归并排序的依赖关系如下图:

分区内并行创建索引-鸿蒙开发者社区

如果采用普通的任务调度器,建索引的逻辑里就必须要处理两种任务之间的依赖关系,并且有部分局部排序失败时,需要记录其状态,会使得建索引本身逻辑变得比较复杂。在OceanBase后台任务调度中,有基于DAG(有向无环图)的调度器,只需要把建索引的所有任务描述成一个有向无环图,调度器能自动按照依赖关系调度任务,并且部分前置依赖任务执行失败时,能够自动的终止建索引的DAG,从而把任务管理从建索引本身逻辑中解耦出来。

外排过程中的临时数据如何存储?

临时排序数据的存储方式有两种选择:

  • 采用OceanBase存储层的宏块来存储
  • 采用临时文件来存储

与使用临时文件来存储相比,采用宏块的存储方式有如下优点:

  • 可以把建索引的资源消耗纳入到OceanBase的资源调度隔离中,方便对建索引过程中租户使用的资源进行控制
  • 一般OceanBase服务器上用于宏块数据文件的空间较大,而临时的空间不太多,因此,使用宏块存储能够避免临时空间不足无法建索引的问题

性能测试

测试场景为,在一个lz4压缩后共440GB的数据表中,构建一张约40GB数据的索引,测试结果如下

分区内并行创建索引-鸿蒙开发者社区


文章转载自公众号:OceanBase


分类
标签
已于2022-10-10 16:14:01修改
收藏
回复
举报
回复
    相关推荐