IoTDB简介
IoTDB 是一款国产自研的物联网原生时序数据库,其技术发源于清华大学,目前已历经 13 年的发展。IoTDB 的诞生,主要是为了解决工业物联网时序数据管理的实时性、压缩比、分布式部署等多方面痛点。
IoTDB具有以下特点:
- 灵活的部署方式
- 云端一键部署
- 终端解压即用
- 终端-云端无缝连接(数据云端同步工具)
- 低硬件成本的存储解决方案
- 高压缩比的磁盘存储(10 亿数据点硬盘成本低于 1.4 元)
- 目录结构的时间序列组织管理方式
- 支持复杂结构的智能网联设备的时间序列组织
- 支持大量同类物联网设备的时间序列组织
- 可用模糊方式对海量复杂的时间序列目录结构进行检索
- 高通量的时间序列数据读写
- 支持百万级低功耗强连接设备数据接入(海量)
- 支持智能网联设备数据高速读写(高速)
- 以及同时具备上述特点的混合负载
- 面向时间序列的丰富查询语义
- 跨设备、跨传感器的时间序列时间对齐
- 面向时序数据特征的计算
- 提供面向时间维度的丰富聚合函数支持
- 极低的学习门槛
- 支持类 SQL 的数据操作
- 提供 JDBC 的编程接口
- 完善的导入导出工具
- 完美对接开源生态环境
- 支持开源数据分析生态系统:Hadoop、Spark
- 支持开源可视化工具对接:Grafana
IoTDB系统架构
-
会话层: 主要提供入口对接各种应用,以及终端用户通过 应用接口发出的事务请求或各种查询要求等。支持各类的语言越多越丰富越好,IoTDB 目前支持 Java原生接口、python、C++、Go、C#、Node.js、Rust、MQTT、Kafka、REST api v1、REST api v2。
-
处理层: 与主流分布式数据库一样, IoTDB基于LSMtree的架构进行设计,数据分为两部分,一个增量数据,一个基线数据,数据达到一定的阀值会一次性提交,存储到硬盘里面。为了数据不丢失,数据会优先写入到wal日志里面,WAL日志、memtable、sstable三者会持续协同。
LSM 由两部分构成: 顺序数据文件空间和乱序数据文件空间。其中乱序数据文件空与LSM 中的L,层级类似,文件间的数据不存在偏序关系;而顺序数据文件空间内的多个文保持了数据在时间戳上的偏序关系,从而大幅度加速时间范围 查询操作,并避免了无效的LSM写放大。
针对存储层的TsFile文件,IoTDB 采用了向量化的数据访问方式。
-
存储层: IoTDB 采用列式文件结构作为数据文件格式,简称TsFile,目前支持hdfs和本地文件系统两种形式。TsFile包括数据区和索引区两部分。在数据区,单个数据序列形成多个数据块,相关序列的多数据块形成数据组。每个数据块又进一步根据操作系统的粒度分为多个数据页。
为了加速度数据访问,每个数据页、数据头又设计了数据段头信息,用于记录该数据页(块)的统计信息,如时间范围、值范围等。
在索引区,TsFile引入了数据组-数据块两级多层索引结构替代其它列式文件的一维数组查找表结构,将数据块定位时间 复杂度降低
IoTDB逻辑架构
从数据库视角来看,IoTDB数据库对象可以理解StorageGroup、Device、Measurement、TimeSeries。
与传统的关系数据库比较 ,StorageGroup相当于database,Device相当于表,Measurement相当于字段,TimeSeries相当于索引, database+Device+Measurement+TimeSeries 确定唯一的数值。
- StorageGroup,从用户角度,主要用于对设备数据进行分组管理;从IoTDB数据库角度,存储组又是一个并发控制和磁盘隔离的单位,不同存储组之间可以并行读写。
- Device,对应现实世界中的具体物理设备,例如:电厂某制造单元、风力发电机、汽车、飞机发动机、地震波采集仪器等。在IoTDB中, device是时序数据一次写入的单位,一次写入请求局限在一个设备中。
- Measurement,对应现实世界中的具体物理设备自身携带的传感器,例如:风力发电机设备上的风速、转向角、发电量等信息采集的传感器。在IoTDB中,Sensor也称为测点(Measurement),具体指传感器采集的某时刻的传感器值,在IoTDB内部采用<time, value>的形式进行列式存储。
- TimeSeries,如其名,对应现实世界的微时间,至少是毫秒级
逻辑视角上以root为根层一级,往下划分是二级StorageGroup存储组/数据库 ,对应软件系统使用资源管理入口,第三级是物联网设备的划分,这里可以被管理的物联网设备,第四级是物联网设备的参数属性。
举例,我们对压力设备和温度设备采集数据。那么我们可以创建两个设备。
#创建压力设备,temperature做存储组
IoTDB> create DATABASE root.temperature;
Msg: The statement is executed successfully.
# 创建设备device1属性type1,数据类型选择text
IoTDB> CREATE TIMESERIES root.temperature.device1.type1 WITH DATATYPE=text, ENCODING=PLAIN;
Msg: The statement is executed successfully.
# 创建设备device1属性content,数据类型选择float
IoTDB> CREATE TIMESERIES root.temperature.device1.content WITH DATATYPE=FLOAT, ENCODING=PLAIN;
Msg: The statement is executed successfully.
#创建压力设备,ln2做存储组,设备名press
IoTDB> create database root.press;
Msg: The statement is executed successfully.
# 创建设备device2属性type1,数据类型选择text
IoTDB> CREATE TIMESERIES root.press.device2.type1 WITH DATATYPE=text, ENCODING=PLAIN;
Msg: The statement is executed successfully.
# 创建设备device2属性content,数据类型选择float
IoTDB > insert into root.temperature.device1.content(timestamp,type1, content) VALUES (1,'name1',0.0001),(2,'name', 0.00002)
# 插入多条数据
IoTDB> insert into root.temperature.device1(timestamp,type1, content) VALUES (1,'name1',0.0001),(2,'name', 0.00002)
Msg: The statement is executed successfully.
# 查询数据
IoTDB> select * from root.temperature.device1;
+-----------------------------+------------------------------+--------------------------------+
| Time|root.temperature.device1.type1|root.temperature.device1.content|
+-----------------------------+------------------------------+--------------------------------+
|1970-01-01T08:00:00.001+08:00| name1| 1.0E-4|
|1970-01-01T08:00:00.002+08:00| name| 2.0E-5|
+-----------------------------+------------------------------+--------------------------------+
Total line number = 2
It costs 0.367s
IoTDB物理架构
从系统视角来看,IoTDB数据库有日志文件 、配置文件、数据文件、预写文件
- 日志文件包括confignode、datenode、
- 配置文件包括iotdb-cluster.properties、iotdb-common.properties、iotdb-confignode.properties、iotdb-datenode.properties。
- 数据文件是数据处理成功刷新到硬盘的数据文件。
- 预写文件优先写入硬盘,假如意外宕机从硬盘里恢复。
IoTDB快速安装
下载介质
wget https://dlcdn.apache.org/iotdb/1.3.1/apache-iotdb-1.3.1-all-bin.zip --no-check-certificate
解压,进入路径,启动服务
bash sbin/start-standalone.sh
命令行登录ioTDB
bash sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root
---------------------
Starting IoTDB Cli
---------------------
_____ _________ ______ ______
|_ _| | _ _ ||_ _ `.|_ _ \
| | .--.|_/ | | \_| | | `. \ | |_) |
| | / .'`\ \ | | | | | | | __'.
_| |_| \__. | _| |_ _| |_.' /_| |__) |
|_____|'.__.' |_____| |______.'|_______/ version 1.3.1 (Build: 214695d)
Successfully login at 127.0.0.1:6667
IoTDB>
IoTDB实践使用
日常使用操作
数据库管理
数据库(Database)类似关系数据库中的 Database,是一组结构化的时序数据的集合。
- 创建数据库
创建一个名为 root.ln 的数据库,语法如下:
CREATE DATABASE root.ln
- 查看数据库
查看所有数据库:
SHOW DATABASES
- 删除数据库
删除名为 root.ln 的数据库:
DELETE DATABASE root.ln
- 统计数据库数量
统计数据库的总数
COUNT DATABASES
时间序列管理
时间序列(Timeseries)是以时间为索引的数据点的集合,在IoTDB中时间序列指的是一个测点的完整序列,本节主要介绍时间序列的管理方式。
- 创建时间序列
需指定编码方式与数据类型。例如创建一条名为root.ln.wf01.wt01.temperature的时间序列:
CREATE TIMESERIES root.ln.wf01.wt01.temperature WITH datatype=FLOAT,ENCODING=RLE
- 查看时间序列
查看所有时间序列:
SHOW TIMESERIES
使用通配符匹配数据库root.ln下的时间序列:
SHOW TIMESERIES root.ln.**
- 删除时间序列
删除名为 root.ln.wf01.wt01.temperature 的时间序列
DELETE TIMESERIES root.ln.wf01.wt01.temperature
- 统计时间序列
统计时间序列的总数
COUNT TIMESERIES root.**
统计某通配符路径下的时间序列数量:
COUNT TIMESERIES root.ln.**
时间序列路径管理
除时间序列概念外,IoTDB中还有子路径、设备的概念。
**子路径:**是一条完整时间序列名称中的一部分路径,如时间序列名称为root.ln.wf01.wt01.temperature,则root.ln、root.ln.wf01、root.ln.wf01.wt01都是其子路径。
**设备:**是一组时间序列的组合,在 IoTDB 中设备是由root至倒数第二级节点的子路径,如时间序列名称为root.ln.wf01.wt01.temperature,则root.ln.wf01.wt01是其设备
- 查看设备
SHOW DEVICES
- 查看子路径
查看 root.ln 的下一层:
SHOW CHILD PATHS root.ln
- 查看子节点
查看 root.ln 的下一层:
SHOW CHILD NODES root.ln
- 统计设备数量
统计所有设备
COUNT DEVICES
- 统计节点数
统计路径中指定层级的节点个数
COUNT NODES root.ln.** LEVEL=2
以下为IoTDB中常用查询语句。
- 查询指定时间序列的数据
查询root.ln.wf01.wt01设备下的所有时间序列的数据
SELECT * FROM root.ln.wf01.wt01
- 查询某时间范围内的时间序列数据
查询root.ln.wf01.wt01.temperature时间序列中时间戳大于 2022-01-01T00:05:00.000 的数据
SELECT temperature FROM root.ln.wf01.wt01 WHERE time > 2022-01-01T00:05:00.000
- 查询数值在指定范围内的时间序列数据
查询root.ln.wf01.wt01.temperature时间序列中数值大于 36.5 的数据:
SELECT temperature FROM root.ln.wf01.wt01 WHERE temperature > 36.5
- 使用 last 查询最新点数据
SELECT last * FROM root.ln.wf01.wt01
时间区域查询
根据一个时间区间选择一列数据
IoTDB> select type, price from root.test.henley where time < 2024-02-18T13:12:38.001+08:00 limit 5;
+-----------------------------+---------------------+----------------------+
| Time|root.test.henley.type|root.test.henley.price|
+-----------------------------+---------------------+----------------------+
|2024-02-18T01:02:00.000+08:00| vechile| 0.46630436|
|2024-02-18T01:02:00.001+08:00| cow| 0.69674313|
|2024-02-18T01:02:00.002+08:00| phone| 0.11488286|
|2024-02-18T01:02:00.003+08:00| house| 0.3449425|
|2024-02-18T01:02:00.004+08:00| vechile| 0.88166314|
+-----------------------------+---------------------+----------------------+
Total line number = 5
It costs 0.470s
根据一个时间区间选择多列数据
IoTDB> select type, price from root.test.henley where time > 2024-02-18T13:12:38.001+08:00 and time < 2024-02-18T13:12:38.10+08:00
+-----------------------------+---------------------+----------------------+
| Time|root.test.henley.type|root.test.henley.price|
+-----------------------------+---------------------+----------------------+
|2024-02-18T13:12:38.002+08:00| car| 0.27619043|
+-----------------------------+---------------------+----------------------+
Total line number = 1
It costs 0.044s
按照多个时间区间选择同一设备的多列数据
IoTDB> select type, price from root.test.henley where (time > 2024-02-18T13:12:38.001+08:00 and time < 2024-02-18T13:12:38.10+08:00) or (time = 2024-02-18T13:12:38.001+08:00);
+-----------------------------+---------------------+----------------------+
| Time|root.test.henley.type|root.test.henley.price|
+-----------------------------+---------------------+----------------------+
|2024-02-18T13:12:38.001+08:00| fish| 0.101163946|
|2024-02-18T13:12:38.002+08:00| car| 0.27619043|
+-----------------------------+---------------------+----------------------+
Total line number = 2
It costs 2.486s
按照多个时间区间选择不同设备的多列数据
IoTDB> select henley.type, henley2.price from root.test where (time > 2024-02-18T13:12:38.001+08:00 and time < 2024-02-18T13:12:38.10+08:00) or (time = 2024-02-18T13:12:38.001+08:00);
+-----------------------------+---------------------+-----------------------+
| Time|root.test.henley.type|root.test.henley2.price|
+-----------------------------+---------------------+-----------------------+
|2024-02-18T13:12:38.001+08:00| fish| null|
|2024-02-18T13:12:38.002+08:00| car| null|
+-----------------------------+---------------------+-----------------------+
Total line number = 2
It costs 0.079s
按照粒度时间去进行查询
在 IoTDB 中,聚合查询可以通过 GROUP BY
子句指定按照时间区间分段聚合。用户可以指定聚合的时间间隔和滑动步长,相关参数如下:
- 参数 1:时间轴显示时间窗口大小
- 参数 2:聚合窗口的大小(必须为正数)
- 参数 3:聚合窗口的滑动步长(可选,默认与聚合窗口大小相同)
#时间区域范围按照1天来进行分组排序
IoTDB> select count(type), max_value(price) from root.test.henley group by ([2024-02-18T03:12:38.001+08:00, 2024-02-25T03:12:38.001+08:00),1d);
+-----------------------------+----------------------------+---------------------------------+
| Time|count(root.test.henley.type)|max_value(root.test.henley.price)|
+-----------------------------+----------------------------+---------------------------------+
|2024-02-18T03:12:38.001+08:00| 660002| 0.99999964|
|2024-02-19T03:12:38.001+08:00| 540000| 0.99999964|
|2024-02-20T03:12:38.001+08:00| 0| null|
|2024-02-21T03:12:38.001+08:00| 0| null|
|2024-02-22T03:12:38.001+08:00| 0| null|
|2024-02-23T03:12:38.001+08:00| 0| null|
|2024-02-24T03:12:38.001+08:00| 0| null|
+-----------------------------+----------------------------+---------------------------------+
Total line number = 7
It costs 48.368s
时间区域范围按照1个小时来进行分组排序
\typoraimg\image-20240605172657335.png)
丰富的UDF函数
当前IoTDB支持数据画像、数据质量、数据修复、数据匹配、异常检测、频域相关、序列发现、字符串处理、数据平滑、数据预测、复杂事件处理,而且UDF方面编程简单方便。
#下载UDF库函数
wget https://dlcdn.apache.org/iotdb/1.3.1/apache-iotdb-1.3.1-library-udf-bin.zip --no-check-certificate
#解压,将library-udf.jar 放在 lib目录下
cp library-udf.jar [lib]目录
# 重启服务,执行register-UDF.sh,显示以下信息,则是加载UDF函数成功
Completeness
本函数用于计算时间序列的完整性。将输入序列划分为若干个连续且不重叠的窗口,分别计算每一个窗口的完整性,并输出窗口第一个数据点的时间戳和窗口的完整性。
IoTDB> select completeness(price) from root.test.henley where time < 2024-02-18T13:12:38.001+08:00;
+-----------------------------+------------------------------------+
| Time|completeness(root.test.henley.price)|
+-----------------------------+------------------------------------+
|2024-02-18T01:02:00.000+08:00| 1.0|
+-----------------------------+------------------------------------+
Total line number = 1
It costs 15.746s
consistency
本函数用于计算时间序列的一致性。将输入序列划分为若干个连续且不重叠的窗口,分别计算每一个窗口的一致性,并输出窗口第一个数据点的时间戳和窗口的时效性。
IoTDB> select consistency(price) from root.test.henley where time < 2024-02-18T13:12:38.001+08:00;
+-----------------------------+-----------------------------------+
| Time|consistency(root.test.henley.price)|
+-----------------------------+-----------------------------------+
|2024-02-18T01:02:00.000+08:00| 1.0|
+-----------------------------+-----------------------------------+
Total line number = 1
It costs 9.989s
Timeliness
本函数用于计算时间序列的时效性。将输入序列划分为若干个连续且不重叠的窗口,分别计算每一个窗口的时效性,并输出窗口第一个数据点的时间戳和窗口的时效性。
IoTDB> select timeliness(price) from root.test.henley where time < 2024-02-18T13:12:38.001+08:00;
+-----------------------------+----------------------------------+
| Time|timeliness(root.test.henley.price)|
+-----------------------------+----------------------------------+
|2024-02-18T01:02:00.000+08:00| 1.0|
+-----------------------------+----------------------------------+
Total line number = 1
It costs 15.647s
validity
本函数用于计算时间序列的有效性。将输入序列划分为若干个连续且不重叠的窗口,分别计算每一个窗口的有效性,并输出窗口第一个数据点的时间戳和窗口的有效性。
IoTDB> select validity(price) from root.test.henley where time < 2024-02-18T13:12:38.001+08:00;
+-----------------------------+--------------------------------+
| Time|validity(root.test.henley.price)|
+-----------------------------+--------------------------------+
|2024-02-18T01:02:00.000+08:00| 1.0|
+-----------------------------+--------------------------------+
Total line number = 1
It costs 7.521s
acf
本函数用于计算时间序列的自相关函数值,即序列与自身之间的互相关函数。
IoTDB> select acf(price) from root.test.henley where time < 2024-02-18T01:02:38.049+08:00;
+-----------------------------+---------------------------+
| Time|acf(root.test.henley.price)|
+-----------------------------+---------------------------+
|1970-01-01T08:00:00.000+08:00| 0.14461020512981726|
|1970-01-01T08:00:00.001+08:00| 0.13553804600169284|
|1970-01-01T08:00:00.002+08:00| 0.0947468206136044|
|1970-01-01T08:00:00.003+08:00| 0.20825145906384496|
|1970-01-01T08:00:00.004+08:00| 0.28996475874840943|
|1970-01-01T08:00:00.005+08:00| 0.22495094075784908|
|1970-01-01T08:00:00.006+08:00| 0.24271618683460874|
|1970-01-01T08:00:00.007+08:00| 0.27530544591467687|
|1970-01-01T08:00:00.008+08:00| 0.2689517084449265|
|1970-01-01T08:00:00.009+08:00| 0.28108957034799975|
|1970-01-01T08:00:00.010+08:00| 0.30070293505366075|
|1970-01-01T08:00:00.011+08:00| 0.3288760446517543|
|1970-01-01T08:00:00.012+08:00| 0.28584150978793116|
|1970-01-01T08:00:00.013+08:00| 0.3271759293151227|
|1970-01-01T08:00:00.014+08:00| 0.3296294811555682|
|1970-01-01T08:00:00.015+08:00| 0.3486298432996775|
|1970-01-01T08:00:00.016+08:00| 0.38040896181043987|
|1970-01-01T08:00:00.017+08:00| 0.3403809709060194|
|1970-01-01T08:00:00.018+08:00| 0.36407499024000656|
|1970-01-01T08:00:00.019+08:00| 0.350659235959142|
IoTDB的UDF函数很丰富
总结
- IoTDB 是一款国人自主研发可控,并且有自主发展技术路径的数据库,具有单机布署和分布式部署多种形态
- IoTDB的系统架构健全,在生态上与hadoop结构有广泛的生态兼容合作
- IoTDB的存储组织与传统关系型数据差不多,这个意味着学习成本不会很高。
- IoTDB 的可用性较高,无论是安装还是使用,都可以快速上手。
- UDF函数是IoTDB 的灵魂,因为里面包含很多与时序相关的操作函数,在时序业务场景,可以快速投入使用。