此文章是对 TDengine的官方文档的笔记整理
1.简介
TDengine 是一款开源、高性能、云原生的时序数据库(Time Series Database, TSDB), 它专为物联网、车联网、工业互联网、金融、IT 运维等场景优化设计。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一款极简的时序数据处理平台。
目前最新版本:v3.0, 官方文档地址:TDengine 文档 | TDengine 文档 | 涛思数据
1.1 特点
- 一个数据采集点一张表与“超级表”概念
- 创新的存储引擎,数据写入、查询、存储效率都大大提升
- 水平扩展能力
- 使用SLQ作为查询语言,且还支持时序数据场景 中插值、降采样、时间加权平均等操作
- 完善的运维支持,对安装、升级、容错灾备、监控TDengine是否健康运行等
- 还支持rest api,支持各种语言进行连接
1.2 基本概念介绍
1.2.1 采集量(Metric)
采集量是指传感器、设备或其他类型采集点采集的物理量,比如电流、电压、温度、压力、GPS 位置等,是随时间变化的,数据类型可以是整型、浮点型、布尔型,也可是字符串。随着时间的推移,存储的采集量的数据量越来越大。
1.2.2 标签(Label/Tag)
标签是指传感器、设备或其他类型采集点的静态属性,不是随时间变化的,比如设备型号、颜色、设备的所在地等,数据类型可以是任何类型。虽然是静态的,但 TDengine 容许用户修改、删除或增加标签值。与采集量不一样的是,随时间的推移,存储的标签的数据量不会有什么变化.
1.2.3 数据采集点(Data Collection Point)
数据采集点是指按照预设时间周期或受事件触发采集物理量的硬件或软件。一个数据采集点可以采集一个或多个采集量,但这些采集量都是同一时刻采集的,具有相同的时间戳。对于复杂的设备,往往有多个数据采集点,每个数据采集点采集的周期都可能不一样,而且完全独立,不同步。
1.2.4 表(Table)
用户需要先建库再建表。
为充分利用其数据的时序性和其他数据特点,TDengine 采取一个数据采集点一张表的策略,要求对每个数据采集点单独建表(比如有一千万个智能电表,就需创建一千万张表,上述表格中的 d1001,d1002,d1003,d1004 都需单独建表),用来存储这个数据采集点所采集的时序数据。这种设计有几大优点:
- 由于不同数据采集点产生数据的过程完全独立,每个数据采集点的数据源是唯一的,一张表也就只有一个写入者,这样就可采用无锁方式来写,写入速度就能大幅提升。
- 对于一个数据采集点而言,其产生的数据是按照时间排序的,因此写的操作可用追加的方式实现,进一步大幅提高数据写入速度。
- 一个数据采集点的数据是以块为单位连续存储的。如果读取一个时间段的数据,它能大幅减少随机读取操作,成数量级的提升读取和查询速度。
- 一个数据块内部,采用列式存储,对于不同数据类型,采用不同压缩算法,而且由于一个数据采集点的采集量的变化是缓慢的,压缩率更高。
TDengine 建议用数据采集点的名字(如上表中的 d1001)来做表名。每个数据采集点可能同时采集多个采集量(如上表中的 current、voltage 和 phase),每个采集量对应一张表中的一列,数据类型可以是整型、浮点型、字符串等。除此之外,表的第一列必须是时间戳,即数据类型为 Timestamp。对采集量,TDengine 将自动按照时间戳建立索引,但对采集量本身不建任何索引。数据用列式存储方式保存。
1.2.5 超级表(STable)
由于一个数据采集点一张表,导致表的数量巨增,难以管理,而且应用经常需要做采集点之间的聚合操作,聚合的操作也变得复杂起来。为解决这个问题,TDengine 引入超级表(Super Table,简称为 STable)的概念。
超级表是指某一特定类型的数据采集点的集合。同一类型的数据采集点,其表的结构是完全一样的,但每个表(数据采集点)的静态属性(标签)是不一样的。描述一个超级表(某一特定类型的数据采集点的集合),除需要定义采集量的表结构之外,还需要定义其标签的 Schema,标签的数据类型可以是整数、浮点数、字符串、JSON,标签可以有多个,可以事后增加、删除或修改。如果整个系统有 N 个不同类型的数据采集点,就需要建立 N 个超级表。
在 TDengine 的设计里,表用来代表一个具体的数据采集点,超级表用来代表一组相同类型的数据采集点集合。
1.2.6 子表(Subtable)
当为某个具体数据采集点创建表时,用户可以使用超级表的定义做模板,同时指定该具体采集点(表)的具体标签值来创建该表。通过超级表创建的表称之为子表。正常的表与子表的差异在于:
- 子表就是表,因此所有正常表的 SQL 操作都可以在子表上执行。
- 子表在正常表的基础上有扩展,它是带有静态标签的,而且这些标签可以事后增加、删除、修改,而正常的表没有。
- 子表一定属于一张超级表,但普通表不属于任何超级表
- 普通表无法转为子表,子表也无法转为普通表。
超级表与基于超级表建立的子表之间的关系表现在:
- 一张超级表包含有多张子表,这些子表具有相同的采集量 Schema,但带有不同的标签值。
- 不能通过子表调整数据或标签的模式,对于超级表的数据模式修改立即对所有的子表生效。
- 超级表只定义一个模板,自身不存储任何数据或标签信息。因此,不能向一个超级表写入数据,只能将数据写入子表中。
查询既可以在表上进行,也可以在超级表上进行。针对超级表的查询,TDengine 将把所有子表中的数据视为一个整体数据集进行处理,会先把满足标签过滤条件的表从超级表中找出来,然后再扫描这些表的时序数据,进行聚合操作,这样需要扫描的数据集会大幅减少,从而显著提高查询的性能。本质上,TDengine 通过对超级表查询的支持,实现了多个同类数据采集点的高效聚合。
1.2.7 库(Database)
库是指一组表的集合。TDengine 容许一个运行实例有多个库,而且每个库可以配置不同的存储策略。不同类型的数据采集点往往具有不同的数据特征,包括数据采集频率的高低,数据保留时间的长短,副本的数目,数据块的大小,是否允许更新数据等等。为了在各种场景下 TDengine 都能最大效率的工作,TDengine 建议将不同数据特征的超级表创建在不同的库里。
一个库里,可以有一到多个超级表,但一个超级表只属于一个库。一个超级表所拥有的子表全部存在一个库里。
1.2.8 FQDN & Endpint
FQDN(Fully Qualified Domain Name,完全限定域名)是 Internet 上特定计算机或主机的完整域名。FQDN 由两部分组成:主机名和域名。例如,假设邮件服务器的 FQDN 可能是 mail.tdengine.com。主机名是 mail,主机位于域名 tdengine.com 中。DNS(Domain Name System),负责将 FQDN 翻译成 IP,是互联网应用的寻址方式。对于没有 DNS 的系统,可以通过配置 hosts 文件来解决。
TDengine 集群的每个节点是由 Endpoint 来唯一标识的,Endpoint 是由 FQDN 外加 Port 组成,比如 h1.tdengine.com:6030。这样当 IP 发生变化的时候,我们依然可以使用 FQDN 来动态找到节点,不需要更改集群的任何配置。而且采用 FQDN,便于内网和外网对同一个集群的统一访问。
2.安装
taosd | 软件包包括服务端 |
taosAdapter | 用于与第三方系统对接并提供 RESTful 接口 |
taosc | 应用驱动 |
CLI,taos、一些工具软件 | 命令行程序 |
2.1 Docker
docker pull tdengine/tdengine:latest
注意:TDengine 3.0 服务端仅使用 6030 TCP 端口。6041 为 taosAdapter 所使用提供 REST 服务端口。6043-6049 为 taosAdapter 提供第三方应用接入所使用端口,可根据需要选择是否打开。
docker run -d -v ~/data/taos/dnode/data:/var/lib/taos \ -v ~/data/taos/dnode/log:/var/log/taos \ -p 6030:6030 -p 6041:6041 -p 6043-6049:6043-6049 -p 6043-6049:6043-6049/udp tdengine/tdengine
/var/lib/taos: TDengine 默认数据文件目录。可通过[配置文件]修改位置。你可以修改~/data/taos/dnode/data为你自己的数据目录
/var/log/taos: TDengine 默认日志文件目录。可通过[配置文件]修改位置。你可以修改~/data/taos/dnode/log为你自己的日志目录
docker ps
docker exec -it <container name> bash
taos
2.2 安装包
TDengine 也提供 Windows x64 平台和 macOS x64/m1 平台的安装包,以及Deb和RPM格式的安装包。
但从官网发现 windows环境 只有TDengine的客户端,没有服务端
2.2.1 运行环境要求
在linux系统中,运行环境最低要求如下:
linux 内核版本 - 3.10.0-1160.83.1.el7.x86_64;
glibc 版本 - 2.17;
如果通过clone源码进行编译安装,还需要满足:
cmake版本 - 3.26.4或以上;
gcc 版本 - 9.3.1或以上;
2.2.2 步骤
从官网下载各自平台的安装包,然后执行安装就可以了
systemctl start taosd
systemctl status taosd
Active: active (running)
Active: inactive (dead)
taos
2.3 云服务
3. 开发指南
支持语言连接:C/C++、Java、Python、Go、Node.js、C#、Rust、Lua(社区贡献)和 PHP (社区贡献)的连接器
3.1 连接方式
- 通过 taosAdapter 组件提供的 REST API 建立与 taosd 的连接,这种连接方式下文中简称“REST 连接”
- 通过客户端驱动程序 taosc 直接与服务端程序 taosd 建立连接,这种连接方式下文中简称“原生连接”。
3.2 连接举例
3.2.1 Java
<dependency>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>3.2.4</version>
</dependency>
package com.taos.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import com.taosdata.jdbc.TSDBDriver;
public class JNIConnectExample {
public static void main(String[] args) throws SQLException {
String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata";
Properties connProps = new Properties();
connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
System.out.println("Connected");
conn.close();
}
}
// use
// String jdbcUrl = "jdbc:TAOS://localhost:6030/dbName?user=root&password=taosdata";
// if you want to connect a specified database named "dbName".
3.2.2 REST连接
public static void main(String[] args) throws SQLException {
String jdbcUrl = "jdbc:TAOS-RS://localhost:6041?user=root&password=taosdata";
Connection conn = DriverManager.getConnection(jdbcUrl);
System.out.println("Connected");
conn.close();
}
public static void main(String[] args) throws SQLException {
String jdbcUrl = "jdbc:TAOS-RS://localhost:6041?user=root&password=taosdata";
Properties connProps = new Properties();
connProps.setProperty(TSDBDriver.PROPERTY_KEY_BATCH_LOAD, "true");
Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
System.out.println("Connected");
conn.close();
}
3.3 操作
3.3.1 库操作
不同类型的数据采集点往往具有不同的数据特征,包括数据采集频率的高低,数据保留时间的长短,副本的数目,数据块的大小,是否允许更新数据等等。为了在各种场景下 TDengine 都能以最大效率工作,TDengine 建议将不同数据特征的表创建在不同的库里,因为每个库可以配置不同的存储策略。创建一个库时,除 SQL 标准的选项外,还可以指定保留时长、副本数、缓存大小、时间精度、文件块里最大最小记录条数、是否压缩、一个数据文件覆盖的天数等多种参数。
CREATE DATABASE power KEEP 365 DURATION 10 BUFFER 16 WAL_LEVEL 1;
3.3.2 表操作
// 创建超级表
CREATE STABLE meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);
// 创建子表
CREATE TABLE d1001 USING meters TAGS ("California.SanFrancisco", 2);
// 当子表d1001不存在时,自动创建
INSERT INTO d1001 USING meters TAGS ("California.SanFrancisco", 2) VALUES (NOW, 10.2, 219, 0.32);
3.4 写入数据
- SQL写入
INSERT INTO d1001 VALUES (ts1, 10.3, 219, 0.31);
INSERT INTO d1001 VALUES (ts1, 10.2, 220, 0.23) (ts2, 10.3, 218, 0.25);
INSERT INTO d1001 VALUES (ts1, 10.3, 219, 0.31) (ts2, 12.6, 218, 0.33) d1002 VALUES (ts3, 12.3, 221, 0.31);
- 从Kafka写入
需要写代码,从kafka的某个topic中获取数据并解析数据,然后拼装成sql,再向TEengine插入
- InfluxDB行协议
需要写代码,使用Schemaless的方式,向向TEengine插入
- OpenTSDB行协议
需要写代码,使用Schemaless的方式,向向TEengine插入
- OpenTSDB JSON 格式协议
需要写代码,使用Schemaless的方式,向向TEengine插入
3.5 查询
- 单列、多列数据查询
- 标签和数值的多种过滤条件:>, , like 等
- 聚合结果的分组(Group by)、排序(Order by)、约束输出(Limit/Offset)
- 时间窗口(Interval)、会话窗口(Session)和状态窗口(State_window)等窗口切分聚合查询
- 数值列及聚合结果的四则运算
- 时间戳对齐的连接查询(Join Query: 隐式连接)操作
- 多种聚合/计算函数: count, max, min, avg, sum, twa, stddev, leastsquares, top, bottom, first, last, percentile, apercentile, last_row, spread, diff 等
3.6 流式计算
- 数据过滤
- 标量函数计算(包含UDF)
- 窗口聚合(支持滑动窗口、会话窗口与状态窗口)
流式计算创建
CREATE STREAM [IF NOT EXISTS] stream_name [stream_options] INTO stb_name AS subquery
stream_options: {
TRIGGER [AT_ONCE | WINDOW_CLOSE | MAX_DELAY time]
WATERMARK time
IGNORE EXPIRED [0 | 1]
}
在subquery中的表有数据进来时,就会执行流式计算,并将处理后的结果插入到stb_name中
3.7 数据订阅
为了帮助应用实时获取写入 TDengine 的数据,或者以事件到达顺序处理数据,TDengine 提供了类似消息队列产品的数据订阅、消费接口。这样在很多场景下,采用 TDengine 的时序数据处理系统不再需要集成消息队列产品,比如 kafka, 从而简化系统设计的复杂度,降低运营维护成本。
与 kafka 一样,你需要定义 topic, 但 TDengine 的 topic 是基于一个已经存在的超级表、子表或普通表的查询条件,即一个 SELECT 语句。你可以使用 SQL 对标签、表名、列、表达式等条件进行过滤,以及对数据进行标量函数与 UDF 计算(不包括数据聚合)。与其他消息队列软件相比,这是 TDengine 数据订阅功能的最大的优势,它提供了更大的灵活性,数据的颗粒度可以由应用随时调整,而且数据的过滤与预处理交给 TDengine,而不是应用完成,有效的减少传输的数据量与应用的复杂度。
消费者订阅 topic 后,可以实时获得最新的数据。多个消费者可以组成一个消费者组 (consumer group), 一个消费者组里的多个消费者共享消费进度,便于多线程、分布式地消费数据,提高消费速度。但不同消费者组中的消费者即使消费同一个 topic, 并不共享消费进度。一个消费者可以订阅多个 topic。如果订阅的是超级表,数据可能会分布在多个不同的 vnode 上,也就是多个 shard 上,这样一个消费组里有多个消费者可以提高消费效率。TDengine 的消息队列提供了消息的 ACK 机制,在宕机、重启等复杂环境下确保 at least once 消费。
// 创建topic
CREATE TOPIC topic_name AS SELECT ts, c1, c2, c3 FROM tmqdb.stb WHERE c1 > 1;
// 列订阅
CREATE TOPIC topic_name as subquery
// 超级表订阅
CREATE TOPIC topic_name [with meta] AS STABLE stb_name [where_condition]
// 数据库订阅
CREATE TOPIC topic_name [with meta] AS DATABASE db_name;
/* 删除 topic */
DROP TOPIC topic_name;
SHOW TOPICS;
SHOW CONSUMERS;
SHOW SUBSCRIPTIONS;
订阅topic等都可以写代码完成,形如订阅kafka的topic,poll到消息后,进行处理
3.8 UDF
可以使用C或python进行UDF的定义
3.9 配置参数
TDengine 系统后台服务由 taosd 提供,可以在配置文件 taos.cfg 里修改配置参数,以满足不同场景的需求。在 Linux 系统上,配置文件的缺省位置在
/etc/taos 目录,在 Windows 系统上缺省位置在 C:\TDengine 。
3.10 文件目录结构
安装 TDengine 后,默认会在操作系统中生成下列目录或文件:
目录/文件 | 说明 |
/usr/local/taos/bin | TDengine 可执行文件目录。其中的执行文件都会软链接到/usr/bin 目录下。 |
/usr/local/taos/driver | TDengine 动态链接库目录。会软链接到/usr/lib 目录下。 |
/usr/local/taos/examples | TDengine 各种语言应用示例目录。 |
/usr/local/taos/include | TDengine 对外提供的 C 语言接口的头文件。 |
/etc/taos/taos.cfg | TDengine 默认[配置文件] |
/var/lib/taos | TDengine 默认数据文件目录。可通过[配置文件]修改位置。 |
/var/log/taos | TDengine 默认日志文件目录。可通过[配置文件]修改位置。 |
3.11 可执行文件
TDengine 的所有可执行文件默认存放在 /usr/local/taos/bin 目录下。其中包括:
- taosd
- taos
- taosdump
- taosBenchmark
- remove.shrmtaos
- taosadapter
- TDinsight.sh
- set_core.sh
- taosd-dump-cfg.gdb
4. 与第三方工具集成
4.1 Grafana
4.2 Prometheus
4.3 Telegraf
4.4 collectd
4.5 StatsD
4.6 icinga2
4.7 TCollector
4.8 EMQX Broker
5. 运维
5.1 容量规划
对服务器的内存、cpu、存储进行规划。
5.2 容错
TDengine使用WAL机制实现,请求的数据先写入数据库日志文件,写入成功后,再删除相应的WAL,如果这个时候断电了,TDengine启动时会先从日志文件中恢复
- wal_level:WAL 级别,1:写 WAL,但不执行 fsync。2:写 WAL,而且执行 fsync。默认值为 1。
- wal_fsync_period:当 wal_level 设置为 2 时,执行 fsync 的周期。设置为 0,表示每次写入,立即执行 fsync。
完全不丢失,则需要将wal_level 设置为2,wal_fsync_period 设置为 0
5.3 灾备
TDengine 灾备是通过在异地的两个数据中心中设置两个 TDengine 集群并利用 taosX 的数据复制能力来实现的
5.4 数据导入
- 按脚本文件导入
TDengine 的 shell 支持 source filename 命令,用于批量运行文件中的 SQL 语句。用户可将建库、建表、写数据等 SQL 命令写在同一个文件中,每条命令单独一行,在 shell 中运行 source 命令,即可按顺序批量运行文件中的 SQL 语句。以‘#’开头的 SQL 语句被认为是注释,shell 将自动忽略。
- 按数据文件导入
insert into tb1 file 'path/data.csv'; 注意:如果 CSV 文件首行存在描述信息,请手动删除后再导入。如某列为空,填 NULL,无引号
- taosdump 工具导入
5.5 数据导出
- 按表导出
select * from <tb_name> >> data.csv;
- 用 taosdump 导出数据
5.6 系统监控
TDinsight - 使用监控数据库 + Grafana 对 TDengine 进行监控的解决方案
6. 原理分析
待实际使用时再分析更新在这里