深度解读 MRS IoTDB 时序数据库的整体架构设计与实现
摘要:本文将会系统地为大家介绍 MRS IoTDB 的来龙去脉和功能特性,重点为大家介绍 MRS IoTDB 时序数据库的整体架构设计与实现。
本文分享自华为云社区《MRS IoTDB时序数据库的总体架构设计与实现》,原文作者:cloudsong。
MRS IoTDB 是华为 FusionInsightMRS 大数据套件最新推出的时序数据库产品,其领先的设计理念在时序数据库领域展现出越来越强大的竞争力,得到了越来越多的用户认可。为了大家更好地了解 MRS IoTDB,本文将会系统地为大家介绍 MRS IoTDB 的来龙去脉和功能特性,重点为大家介绍 MRS IoTDB 时序数据库的整体架构设计与实现。
1. 什么是时序数据库
时序数据库是时间序列数据库的简称,指的是专门对带时间标签(按照时间的顺序变化,即时间序列化)的数据进行存储、查询、分析等处理操作的专用数据库系统。通俗来说,时序数据库就是专门用来记录例如物联网设备的温度、湿度、速度、压力、电压、电流以及证券买入卖出价等随着时间演进不断变化的各类数值(测点、事件)的数据库。
当前,随着大数据技术发展和应用的不断深入,以物联网 IoT(InternetOf Things)、金融分析为代表的两类数据,表现出随着时间的演进连续不断地产生大量传感器数值或事件数据。时间序列数据(timeseries data)就是以数据(事件)发生的时刻(时间戳)为时间轴形成的连续不断的数值序列。例如某物联网设备不同时刻的的温度数据构成一个时间序列数据:
无论是机器产生的传感器数据,还是人类活动产生的社会事件数据,都有一些共同的特征:
(1)采集频率高:每秒采集几十次、上百次、十万次乃至百万次;
(2)采集精度高:最少支持毫秒级采集,有些需要支持微秒级和纳秒级采集;
(3)采集跨度大:7*24 小时持续不断地连续采集几年、乃至数十年数据;
(4)存储周期长:需要支持时序数据的持久存储,甚至对有些数据需要进行长达上百年的永久存储(例如地震数据);
(5)查询窗口长:需要支持从毫秒、秒、分钟、小时到日、月、年等不同粒度的时间窗口查询;也需要支持万、十万、百万、千万等不同粒度的数量窗口查询;
(6)数据清洗难:时间序列数据存在乱序、缺失、异常等复杂情况,需要专用算法进行高效实时处理;
(7)实时要求高:无论是传感器数据还是事件数据,都需要毫秒级、秒级的实时处理能力,以确保对实时响应和处理能力;
(8)算法专业强:时间序列数据在地震、金融、电力、交通等不同领域,都有很多垂直领域的专业时序分析需求,需要利用时序趋势预测、相似子序列。
分析、周期性预测、时间移动平均、指数平滑、时间自回归分析以及基于 LSTM 的时序神经网络等算法进行专业分析。
从时序数据的共同特征可以看出,时间序列特殊的场景需求给传统的关系数据库存储和大数据存储都带来了挑战,无法是采用关系数据库进行结构化存储,还是采用 NoSQL 数据库进行存储,都无法满足海量时序数据高并发实时写入和查询的需求。因此,迫切需要一种专门用于存储时间序列数据的专用数据库,时序数据库的概念和产品就这样诞生了。
需要注意的是:时序数据库不同于时态数据库和实时数据库。时态数据库(TemporalDatabase)是一种能够记录对象变化历史,即能够维护数据的变化经历的数据库,比如 TimeDB。时态数据库是对传统关系数据库中时间记录的时间状态进行细粒度维护的系统,而时序数据库完全不同于关系数据库,只存储不同时间戳对应的测点值。有关时序数据库与时态数据库的更详细对比,后续将会发文专门介绍,在此不再详述。
时序数据库也不同于实时数据库。实时数据库诞生于传统工业,主要是因为现代工业制造流程及大规模工业自动化的发展,传统关系数据库难以满足工业数据的存储和查询需求。因此,在 80 年代中期,诞生了适用于工业监控领域的实时数据库。由于实时数据库诞生早,在扩展性、大数据生态对接、分布式架构、数据类型等方面存在局限,但是也有产品配套齐全、工业协议对接完整的优势。时序数据库诞生于物联网时代,在大数据生态对接、云原生支持等方面更有优势。
时序数据库与时态数据库、实时数据库的基本对比信息如下:
2.什么是 MRS IoTDB 时序数据库
MRS IoTDB 是华为 FusionInsightMRS 大数据套件中的时序数据库产品,在深度参与 ApacheIoTDB 社区开源版的基础上推出的高性能企业级时序数据库产品。IoTDB 顾名思义,是针对 IoT 物联网领域推出的专用时序数据库软件,是由清华大学发起的国产 Apache 开源软件。自 IoTDB 诞生之初,华为就深度参与 IoTDB 的架构设计和核心代码贡献,对 IoTDB 集群版的稳定性、高可用和性能优化投入了大量人力并提出了大量的改进建议和贡献了大量的代码。
IoTDB 在设计之初,全面分析了市面上的时序数据库相关产品,包括基于传统关系数据库的 Timescale、基于 HBase 的 OpenTSDB、基于 Cassandra 的 KariosDB、基于时序专属结构的 InfluxDB 等主流时序数据库,借鉴了不同时序数据在实现机制方面的优势,形成了自己独特的技术优势:
(1)支持高速数据写入
独有的基于两阶段 LSM 合并的 tLSM 算法有效保障了 IoTDB 即使在乱序数据存在的情况下也能轻松实现单机每秒千万测点数据的并发写入能力。
(2)支持高速查询
支持 TB 级数据毫秒级查询
(3)功能完备
支持 CRUD 等完整的数据操作(更新通过对同一设备同一时间戳的测点数据覆盖写入来实现,删除通过设置 TTL 过期时间来实现),支持频域查询,具备丰富的聚合函数,支持相似性匹配、频域分析等专业时序处理。
(4)接口丰富,简单易用
支持 JDBC 接口、Thrift API 接口和 SDK 等多种接口。采用类 SQL 语句,在标准 SQL 的语句上增加了对于时间滑动窗口的统计等时序处理常用的功能,提供了系统使用效率。Thrift API 接口支持 Java、C\C++、Python、C#等多语言接口调用。
(5)低存储成本
IoTDB 独立研发的 TsFile 时序文件存储格式,专门针对时序处理处理做了优化,基于列式存储,支持显式的数据类型声明,不同数据类型自动匹配 SNAPPY、LZ4、GZIP、SDT 等不同的压缩算法,可实现 1:150 甚至更高的压缩比(数据精度进一步降低的情况下),极大地降低了用户的存储成本。例如某用户原来用 9 台 KariosDB 服务器存储的时序数据,IoTDB 用 1 台同等配置的服务器即可轻松实现。
(6)云边端多形态部署
IoTDB 独有的轻量级架构设计保障了 IoTDB 可以轻松实现“一套引擎打通云边端,一份数据兼容全场景”。在云服务中心,IoTDB 可以采用集群部署,充分发挥云的集群处理优势;在边缘计算位置,IoTDB 可以在边缘服务器上部署单机 IoTDB,也可以部署少量节点的集群版,具体视边缘服务器配置而定;在设备终端,IoTDB 可以 TsFile 文件的形态直接嵌入到终端设备的本地存储中,并直接被设备终端的直接读写 TsFile 文件,不需要 IoTDB 数据库服务器的启动运行,极大地减少了对终端设备处理能力的要求。由于 TsFile 文件格式开放,终端任意语言和开发平台可以直接读写 TsFile 的二进制字节流,也可以利用 TsFile 自带的 SDK 进行读写,对外甚至可以通过 FTP 将 TsFile 文件发送到边缘或云服务中心。
(7)查询分析一体化
IoTDB 一份数据同时支持实时读写与分布式计算引擎分析,TsFile 与 IoTDB 引擎的松耦合设计保障了一方面 IoTDB 可以利用专有的时序数据处理引擎对时序数据进行高效写入和查询,同时 TsFile 也可以被 Flink、Kafka、Hive、Pulsar、RabbitMQ、RocketMQ、Hadoop、Matlab、Grafana、Zeepelin 等大数据相关组件进行读写分析,极大地提升了 IoTDB 的查询分析一体化能力和生态扩展能力。
3. MRS IoTDB 的整体架构
MRS IoTDB 在 ApacheIoTDB 已有架构的基础上,融合 MRS Manager 强大的日志管理、运维监控、滚动升级、安全加固、高可用保障、灾备恢复、细粒度权限管控、大数据生态集成、资源池优化调度等企业级核心能力,对 ApacheIoTDB 内核架构尤其是分布式集群架构做了大量的重构优化,在稳定性、可靠性、可用性和性能方面做了大量的系统级增强。
(1)接口兼容性:
进一步完善北向接口和南向接口,支持 JDBC、Cli、API、SDK、MQTT、CoAP、Https 等多种访问接口,进一步完善类 SQL 语句,兼容大部分 Influx SQL,支持批量导入导出
(2)分布式对等架构:
MRS IoTDB 在基于 Raft 协议的基础上,采用了改进的 Multi-Raft 协议,并对 Muti-Raft 协议的底层实现进行了优化,采用了 CacheLeader 等优化策略在保障无单节故障的基础上,进一步提升 MRS IoTDB 数据查询路由的性能;同时,对强一致性、中等一致性和弱一致性策略进行了细粒度优化;对一致性哈希算法加入虚拟节点策略避免数据倾斜,同时融合了查表与哈希分区的算法策略,在提升集群高可用的基础上进一步保障集群调度的性能。
(3)双层粒度元数据管理:由于采用了对等架构,元数据信息自然分布在集群所有节点上进行存储,但是由于元数据的存储量较大会带来内存的较大消耗。为了平衡内存消耗与性能,MRS IoTDB 采用了双层粒度元数据管理架构,首先在所有节点间进行时间序列组元数据的同步,其次在分区节点间进行时间序列元数据的同步。这样在查询元数据的时候,首先会基于时间序列组进行过滤树剪枝,大大减少搜寻空间,然后在进一步在过滤后的分区节点进行时间序列元数据的查询。
(4)本地磁盘高性能访问:
MRS IoTDB 采用专用的 TsFile 文件格式进行时间序列优化存储,采用列存格式进行自适应编码与压缩,支持流水线优化访问和乱序数据高速插入
(5)HDFS 生态集成:
MRS IoTDB 支持 HDFS 文件读写,并对 HDFS 进行了本地缓存、短路读、HDFS I/O 线程池等多种优化手段,全面提升 MRS IoTDB 对 HDFS 的读写性能,同时,MRS IoTDB 支持华为 OBS 对象存储并进行了更加高性能的深度优化。
在 HDFS 集成的基础上,MRS IoTDB 支持 Spark、Flink、Hive 等 MRS 组件对 TsFile 的高效读写。
(6)多级权限管控:
支持存储组、设备、传感器等多级权限管控
支持创建、删除、查询等多级操作
支持 Kerberos 认证
支持 Ranger 权限架构
(7)云边端部署:
支持云边端灵活部署,边缘部分可以基于华为的 IEF 产品进行对接,也可以直接部署在华为的 IES 中。
MRS IoTDB 集群版支持动态扩缩容,可以为云边端提供更加灵活的部署支持。
4. MRS IoTDB 的单机架构
4.1 MRS IoTDB 的基础概念
MRS IoTDB 主要聚焦在 IoT 物联网领域的设备传感器测点值的实时处理,因此,MRS IoTDB 的基础架构设计以设备、传感器为核心概念,同时为了便于用户使用和 IoTDB 管理时间序列数据,增加了存储组的概念,下面为大家分别解释一下:
存储组(StorageGroup): IoTDB 为了管理时序数据提出的一个概念,类似于关系数据库中的数据库的概念。从用户角度,主要用于对设备数据进行分组管理;从 IoTDB 数据库角度,存储组又是一个并发控制和磁盘隔离的单位,不同存储组之间可以并行读写。
设备 (Device):对应现实世界中的具体物理设备,例如:电厂某制造单元、风力发电机、汽车、飞机发动机、地震波采集仪器等。在 IoTDB 中, device 是时序数据一次写入的单位,一次写入请求局限在一个设备中。
传感器(Sensor): 对应现实世界中的具体物理设备自身携带的传感器,例如:风力发电机设备上的风速、转向角、发电量等信息采集的传感器。在 IoTDB 中,Sensor 也称为测点(Measurement),具体指传感器采集的某时刻的传感器值,在 IoTDB 内部采用<time, value>的形式进行列式存储。
存储组、设备、传感器的关系如下面的例子:
时间序列(TimeSeries): 类似于关系数据库中的一张表,不过这张表主要有时间戳(Timestamp)、设备 ID(Device ID)、测点值(Measurement)三个主要字段。为了便于对时间序列的设备信息进行更多描述,IoTDB 还增加了 Tag 和 Field 等扩展字段,其中 Tag 支持索引,Field 不支持索引。在有的时序数据库中,又称为时间线,表示记录某设备某传感器值随着时间不断变化的值,形成一条沿着时间轴不断追加测点值的时间线。
路径(Path):IoTDB 构造了一个以 root 为根节点、把存储组、设备、传感器串联在一起的树形结构,从 root 根节点经过存储组、设备到传感器叶子节点,构成了一条路径。如下图所示:
虚拟存储组:由于存储组的概念具有用户对设备分组和系统进行并发控制的双重作用,二者的过度耦合会造成用户的不同使用方式对系统并发控制的影响。例如:用户把不相关的所有设备数据都放到一个存储组中,IoTDB 对这个存储组加锁进行并发控制,限制了数据的并发读写能力。为了是实现存储组与并发控制的相对松耦合,IoTDB 设计了虚拟存储组这个概念,把对存储组的并发控制细粒度拆分到虚拟存储组这个粒度,从而减少了并发控制的粒度。
4.2 MRS IoTDB 的基本架构
单机 MRS IoTDB 主要不同的存储组构成,每个存储组是一个并发控制和资源隔离单位,每个存储组里面包括了多个 TimePartition。其中,每个存储组对应一个 WAL 预写日志文件和 TsFile 时序数据存储文件。每个 TimePartition 中的时序数据先写入 Memtable,同时记入 WAL,定时异步刷盘到 TsFile,具体实现机制后续会给大家详细介绍。MRS IoTDB 单机的基本架构如下:
5. MRS IoTDB 的集群架构
5.1 基于 Multi-Raft 的分布式对等架构
MRS IoTDB 集群是完全对等的分布式架构,既基于 Raft 协议避免了单点故障问题,又通过 Multi-Raft 协议避免了单一 Raft 共识组带来的单点性能问题,同时对分布式协议的底层通讯、并发控制和高可用机制做了进一步优化。
首先,整个集群的所有节点构成一个元数据组(MetaGroup),只用于维护存储组的元数据信息。例如下图蓝灰色框所示的一个 4 节点的 IoTDB 集群,全部 4 个节点构成一个元数据组(MetaGroup);
其次,根据数据副本数构造数据组。例如副本数为 3,则构造一个包括 3 个节点的数据组(DataGroup)。存储组用于存储时间序列数据及对应的元数据。
分布式系统中通常以多副本的方式实现数据的可靠存储。同一份数据的多个副本存储在不同的节点中且必须保证一致,因此需要使用 Raft 共识协议来保证数据的一致性,它将一致性的问题拆分成了几个相对独立的子问题,即领导者选举、日志复制、一致性保证等。Raft 协议中有以下重要的概念:
(1)Raft 组。Raft 组中有一个通过选举产生的 leader 节点,其他节点是 follower。当一个写入请求到来时,首先要提交给 leader 节点处理,leader 节点先在自己的日志里面记录下这个写入请求,然后将这条日志分发到 follower 节点。
(2)Raft 日志。Raft 通过日志的方式保证操作不会丢失,日志中维护了一个 Commit 编号和 Apply 编号。如果一条日志被 Commit,就代表目前集群中超过半数的节点都收到并持久化了这条日志。如果一条日志被 Apply,就表示当前节点执行了这条日志。当某些节点出现故障并重新恢复时,该节点的日志就会落后于 leader 的日志。则在这个节点追上 leader 的日志之前,它不能向外界正常提供服务。
5.2 元数据分层管理
元数据管理策略是 MRS IoTDB 分布式设计中的要点。在进行元数据管理策略设计时首先要考虑元数据在读写流程中的用途:
写入数据时需要元数据进行数据类型、权限等合法性检查
查询数据时需要元数据进行查询路由。同时,由于时序数据场景中元数
据庞大,还需要考虑元数据对内存资源的消耗。
现有的元数据管理策略要么采用将元数据交由元数据节点专门管理的方式,这种方法会降低读写性能; 要么采用在集群所有节点全量保存元数据的方式,这种方式会消耗大量的内存资源。
为了解决上述问题,MRS IoTDB 设计了双层粒度元数据管理策略,其核心思想是通过将元数据拆分为存储组和时间序列两层分别管理:
(1)存储组元数据:元数据组(MetaGroup)包含了查询数据时的路由信息,存储组(StorageGroup)的元数据信息在集群所有节点上全量保存。存储组的粒度较大,一个集群内部的存储组数量级远远小于时间序列的数量级。因此在集群所有节点上对这些存储组元数据的保存,大大减少了内存的占用。
元数据组中的每个节点称为元数据持有者,采用 Raft 协议来保证每个持有者与同组的其他持有者的数据一致性。
(2)时间序列元数据:数据组(DataGroup)中的时间序列元数据中包含了数据写入时需要的数据类型、权限等信息,这些信息保存在数据组所在节点(集群部分节点)上。由于时间序列元数据的粒度较小,数量远远多于存储组元数据,因此这些时间序列元数据保存在数据组所在的节点上,避免了不必要的内存占用,同时也能通过存储组元数据的一级过滤快速定位,同时数据组的 Raft 一致性也避免了时间序列元数据存储的单点故障。
数据组中的每个节点称为数据分区持有者,采用 Raft 协议来保证每个持有者与同组的其他持有者的数据一致性。
该方法将元数据按存储组和时间序列两层粒度分别在元数据持有者和数据分区持有者中管理,由于时间序列数据和元数据在数据组内同步,因此每次数据写入不需要进行元数据的检查与同步操作,仅需要在修改时间序列元数据时进行存储组元数据的检查与同步操作,从而提高系统性能。例如创建一个时间序列并进行 50 万次数据写入的操作中,元数据检查与同步操作从 50 万次降至 1 次**。**
5.3 元数据分布
根据元数据分层管理可知,元数据分为存储组元数据和时间序列元数据。
存储组元数据在全集群所有的节点上都有副本,属于 MetaGroup 组。
时间序列元数据只在对应的 DataGroup 上存储,存储一些时间序列的属性,字段类型,字段描述等信息。时间序列元数据的分布方式和数据分布方式一样,都是通过 slot hash 产生。
5.4 时间序列数据分布
分布式系统实现中基于哈希环和环上查找算法将时序数据按照存储组进行分区。将集群各个节点按哈希值放到哈希环上,对于到来的一个时间序列数据点,计算这个时间序列名称所对应的存储组的哈希值并放置到哈希环上,在环上按顺时针方向进行搜索,找到的第 1 个节点就是要插入的节点。
使用哈希环进行数据分区时,容易出现两个节点的哈希值的差较小的情况,因此在使用一致性哈希环的基础上引入虚拟节点,具体做法是将每个物理节点虚拟成若干个,并将这些虚拟节点按照哈希值放置到哈希环上,在很大程度上避免了数据倾斜的情况,使数据分布得更加均匀。
首先,整个集群预设 10000 个 slot,均匀将此 10000 个 slot 分布在各个 DataGroup 上。如下图所示,IoTDB 集群有 4 个 DataGroup,整个集群有 10000 个 slot,则平均每个 DataGroup 有 10000/4=2500 个 slot.由于 DataGroup 的数量等于集群节点数 4,也就相当于平均每个节点 2500 个 slot.
其次, 完成 slot 到 DataGroup、Time Partition 和 time series 的映射。
IoTDB 集群根据 raft 协议划分成多个 DataGroup 组,每一个 DataGroup 组中包含多个 slot,而每一个 slot 中包含多个 time partition,同时每一个 time partition 中包含多个 time series,构成关系如下图所示:
最后,通过 Hash 计算 slot 的值,完成输入存储组和时间戳到 slot 的映射:
1)先按时间范围分区,利于时间范围查询:
TimePartitionNum = TimeStamp %PartitionInterval
其中 TimePartitionNum 是时间分区的 ID,TimeStamp 是待插入测点数据的时间戳,PartitionInterval 是时间分区间隔,默认是 7 天。
2)再按存储组分区,通过 Hash 计算出 slot 的值:
Slot = Hash(StorageGroupName + TimePartitionNum) % maxSlotNum
其中 StorageGroupName 是存储组的名字,TimePartitionNum 是第 1 步计算出的时间分区 ID,maxSlotNum 是最大 slot 数,默认 10000。
Data Group 和 StorageGroup 的关系如下图所示,其中节点 3 和节点 1 上的 Data Group 1 展示的是同一个 Data Group 分布在两个节点上的情形:
点击关注,第一时间了解华为云新鲜技术~
作者:华为云开发者社区
链接:https://juejin.cn/post/6978679455199805477
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。