【转载】Apache IoTDB 分布式数据分布

Apache IoTDB [1] 从 2018 年 11 月捐赠给 Apache 基金会,成为孵化项目,到 2020 年 9 月毕业,期间经历了 0.8-0.11 4 个大的版本,但都是单机版本,社区对 Apache IoTDB 的分布式版本呼声也越来越高。2021 年 4 月,Apache IoTDB 0.12 版本的发布,带来了一个期盼已久的好消息:Apache IoTDB 0.12 开始支持分布式。今天我们就来看一下 Apache IoTDB 分布式中的数据分布。

分布式架构

IoTDB 采用 Share-Nothing 的分布式架构 (这里指的是数据存本地磁盘的情况下,IoTDB 也支持数据存储到 HDFS 上面,这种情况本文暂且不表),各个节点都是同质的,每个节点主要模块如下图所示:

image.png

单机有如下几大模块:分别为 Physical Plan Generator、SQL Parser、Single Read/Write Engine 以及存储文件 TsFile。分布式较单机多了如下几大模块:Data Partition、Distributed Query、Distributed Write 以及各个节点之间同步协议 Raft Synchronization 模块。

IoTDB 集群搭建之后,会根据节点的 ip 和 port 和当前启动时间生成一个 hash 值,所有节点按照此 hash 值排序形成一个环形,hash 值最大的节点的后面的节点就是 hash 值最小的节点,集群会按照配置的副本数 N,从 hash 值最小的节点开始,依次选择 N-1 个节点组成一个 raft 组,形成一个 data raft group。所有的 meta 节点组成一个 meta raft group。

image.png

以 4 节点 3 副本为例,其会形成如下 raft 复制组,每个节点上面都会有 N+1 个复制组,N 是副本数,即 N 个 data raft group,1 指的是所有节点形成一个 meta raft group。

image.png

分布式数据存储

当初始化好了 raft 复制组之后,面临的问题就是数据归属问题,哪些 raft 复制组处理哪些数据呢?这就需要数据分区这个模块来解决了。

数据分区模块负责元数据、数据分布的计算工作,为了便于表述,本文在此讲述下 IoTDB 的一些基础概念。

IoTDB 基础概念

IoTDB 模型是树状结构。如下所示,有存储组、设备、测点等概念。存储组可以理解为传统数据库中的表,在存储的时候,不同存储组的数据是存储在不同的文件夹中的。下图中有root.sgccroot.ln两个存储组。叶子节点叫做测点,叶子节点的父节点叫做设备。从父节点 root 到叶子节点的全路径叫做时序。比如下图中有root.sgcc.wf01.status等 4 条时序。关于这些概念的详细描述,请参考 IoTDB 官方网站 [1]。

image.png

元数据分布

对于分布式 IoTDB 来说,有两种类型的元数据信息,一种是存储组、另外一种是时序。为什么说两种类型的元数据呢?因为这两种元数据是不同的复制组管理的。存储组是 meta raft group 管理的。而时序信息是由 data raft group 管理的。这样做的好处也是由于存储组元数据比较少,可以在各个节点保存;但是时序信息有可能比较大,有可能高达千万级别,如果每个节点都保存有相同的时序信息,每个节点会浪费太多的内存空间 (这里也是内存和时间的 trade off,当然每个节点都有时序的元数据信息是最好的,因为写入、查询会用到这些时序元数据信息。这里将在后面的文章中进行分析)。所以会把这些时序数据信息分散到各个节点进行管理。

存储组分布

对于存储组这样的元数据,由于是 meta raft group 管理的。所以在每个节点都会保存。

时序分布

对于时序和数据的存储,是分布到多个节点进行分散存储的。分布的核心是一个数据分区算法,即如何判定我的 (元) 数据应该存储在哪台机器上?

IoTDB 系统中预先设置了 10000 个 slot,然后会均匀的把这些 slot 分到集群中各个 IoTDB 实例中,假设节点数是 M,则集群环中的前 M-1 个节点每个节点分配的 slot 数是10000/M,最后一个节点是 slot 数就是10000-10000/M*(M-1),可能较前 M-1 个节点会多一些。

比如,在 6 个节点组成的集群中,第一个节点会分配 0-1665 共 1666 个 slot;第二个节点会分配 1666-3331 共 1666 个 slot;第三个节点会分配 3332-4997 共 1666 个 slot;第四个节点会分配 4998-6663 共 1666 个 slot;第五个节点会分配 6664-8329 共 1666 个 slot;而第六个节点就会分配 8330-9999 共 1670 个 slot

image.png

得到了节点和 slot id 的关系,剩下的就是如何把数据映射到 slot 中。

IoTDB 采用了如下 hash 算法:

slot_id = hash(storage_group, time_partition) % total_slot_num

storage_group 即存储组的名字,time_partition 会根据元数据操作还是数据操作,执行不同的策略。

在计算时序的分布的时候,time_partition 永远等于 0,即可以理解为同一个存储组的所有时序都是保存在同一个 data raft 组中的。

数据分布

数据分布与时序元数据分布的计算公式都是一致的,区别在于其 time_partition 不是 0,而是计算出来的。

time_partition = time_stamp % partition_interval

如上所示,time_stamp 是数据插入的时间戳,而 partition_interval 是时间分区,比如一周、一个月等。由于同一个时间分区的数据是保存在一起的,对于查询和过期数据删除都有优势。

如下所示,每个 data raft group 会有许多的 slot,每个 slot 上面会有多个 time partition,每个 partition 会有多个 TsFile,一个 TsFile 会有属于这个时间分区的多条时序的具体数据,关于 TsFile 的详细描述,请参考官网 TsFile 介绍 [2]。

image.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容