在 TDengine 中如何高效写入?四种写入方式提效大全

小 T 导读:众所周知,TDengine 支持多种写入协议,包括 SQL、InfluxDB Line 协议、OpenTSDB Telnet 协议、OpenTSDB JSON 格式协议。但说到如何进行写入操作,很多读者可能都是一头雾水,本篇文章为大家汇总了一系列的写入教程,方便有需要的开发者作为写入指南收藏使用。

TDengine 中的 SQL 写入即模式化写入,在写入到 Database 之前,需要预先定义好数据表的 Schema 模式,具体来说就是数据表包含多少列,每列存放的数据类型是什么。即在建表时使用标准的 SQL 语句指定表的 Schema,再遵照预先建好的列跟标签值的数量和类型进行数据写入。

除了 SQL 写入外, TDengine 还支持三种无模式写入协议,分别是 InfluxDB Line 协议、OpenTSDB Telnet 协议和 OpenTSDB JSON 格式协议。如果你对 NoSQL 比较熟悉,那对无模式写入应该就不会陌生了。通俗来讲,无模式写入为用户提供了一种以文本格式将数据写入到 TDengine 的方式,更加便捷。

物联网场景中的应用经常需要采集比较多的数据项,用于实现智能控制、业务分析和设备监控等,由于应用逻辑的版本升级,或者设备自身的硬件调整等原因,数据采集项有可能比较频繁地出现变动,为了在这种情况下仍能方便地完成数据记录工作,TDengine 从 2.2 版本开始就提供了无模式写入方式,写入时无需提前创建超级表和子表,其引擎能自适应数据并对表结构进行调整。

在使用 TDengine 写入数据时,数据可以单条插入,也可以批量插入,可以插入一个数据采集点的数据,也可以同时插入多个数据采集点的数据。此外,TDengine 不仅支持多线程插入、时间乱序数据插入,也支持历史数据插入。下面将对四种写入协议进行说明,以供参考。

SQL 写入

用户可以让应用通过连接器执行 INSERT 语句来插入数据,还可以通过 TAOS Shell,手动输入 INSERT 语句来实现。

  • 一次写入一条

下面这条 INSERT 就将一条记录写入到表 d1001 中:

INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31);
  • 一次写入多条

TDengine 支持一次写入多条记录,比如下面这条命令就将两条记录写入到表 d1001 中:

INSERT INTO d1001 VALUES (1538548684000, 10.2, 220, 0.23) (1538548696650, 10.3, 218, 0.25);
  • 一次写入多表

TDengine 也支持一次向多个表写入数据,比如下面这条命令就向 d1001 写入两条记录,向 d1002 写入一条记录:

INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31) (1538548695000, 12.6, 218, 0.33) d1002 VALUES (1538548696800, 12.3, 221, 0.31);
  • 注意事项

如果想要提高写入效率,我们可以使用批量写入,这样一批写入的记录条数越多,插入效率就会越高,但需要注意的是,一条记录不能超过 48 KB,一条 SQL 语句总长度不能超过 1MB。此外,TDengine 支持多线程同时写入,如果要进一步提高写入速度,一个客户端需要打开 20 个以上的线程同时写。但要注意,线程数达到一定数量后将无法再提高,甚至还会下降,因为线程频繁切换会带来额外开销。

对同一张表来说,如果新插入记录的时间戳已经存在,那默认情形下(UPDATE=0)新记录将被直接抛弃,也就是说,在一张表里时间戳必须是唯一的。如果让应用自动生成记录,很可能生成的时间戳是一样的,这样一来,成功插入的记录条数就会小于应用插入的记录条数。如果在创建 Database 时使用了 UPDATE 为 1 的选项,插入相同时间戳的新记录将覆盖原有记录。

最后一点,写入数据的时间戳必须大于当前时间减去配置参数 keep 的时间,如果 keep 配置为 3650 天,那么将无法写入比 3650 天还早的数据;而且写入数据的时间戳也不能大于当前时间加配置参数 days,即如果 days 为 2,那么也将无法写入比当前时间还晚 2 天的数据。

关于 SQL 写入的更详细语法规则可参考此前发布的使用 TDengine 如何进行 SQL 写入 一文。

InfluxDB 行协议

InfluxDB Line 协议采用一行字符串来表示一行数据。分为四部分:

measurement,tag_set field_set timestamp
  • measurement 将作为超级表名。它与 tag_set 之间使用一个英文逗号来分隔。
  • tag_set 将作为标签数据,其格式形如 <tag_key>=<tag_value>,<tag_key>=<tag_value>,也即可以使用英文逗号来分隔多个标签数据。它与 field_set 之间使用一个半角空格来分隔。
  • field_set 将作为普通列数据,其格式形如 <field_key>=<field_value>,<field_key>=<field_value>,同样是使用英文逗号来分隔多个普通列的数据。它与 timestamp 之间使用一个半角空格来分隔。
  • timestamp 即本行数据对应的主键时间戳。

例如:

meters,location=California.LosAngeles,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611249500
  • 注意事项
    • tag_set 中的所有数据会自动转化为 nchar 数据类型;
    • field_set 中的每个数据项都需要对自身的数据类型进行描述,比如 1.2f32 代表 float 类型的数值 1.2,如果不带类型后缀会被当作 double 处理;
    • timestamp 支持多种时间精度。写入数据时需要用参数指定时间精度,支持从小时到纳秒的 6 种时间精度。

OpenTSDB 行协议

OpenTSDB 行协议同样采用一行字符串来表示一行数据。由于 OpenTSDB 采用的是单列模型,因此一行只能包含一个普通数据列,但标签列依然可以有多个。该协议同样分为四部分,具体格式约定如下:

<metric> <timestamp> <value> <tagk_1>=<tagv_1>[ <tagk_n>=<tagv_n>]

需要注意的是:

  • metric 将作为超级表名。
  • timestamp 为本行数据对应的时间戳。根据时间戳的长度自动识别时间精度。支持秒和毫秒两种时间精度
  • value 为度量值,必须为一个数值。对应的列名也是 “value”。
  • 最后一部分是标签集, 用空格分隔不同标签, 所有标签自动转化为 nchar 数据类型;

例如:

meters.current 1648432611250 11.3 location=California.LosAngeles groupid=3

具体可以参考 OpenTSDB Telnet API 文档:http://opentsdb.net/docs/build/html/api_telnet/put.html

OpenTSDB JSON 格式协议

OpenTSDB JSON 格式协议采用一个 JSON 字符串表示一行或多行数据。例如:

[
  {
    "metric": "sys.cpu.nice",
    "timestamp": 1346846400,
    "value": 18,
    "tags": {
      "host": "web01",
      "dc": "lga"
    }
  },
  {
    "metric": "sys.cpu.nice",
    "timestamp": 1346846400,
    "value": 9,
    "tags": {
      "host": "web02",
      "dc": "lga"
    }
  }
]

与 OpenTSDB 行协议类似,在此种写入协议中,metric 将作为超级表名, timestamp 表示时间戳,value 表示度量值, tags 表示标签集。具体可以参考 OpenTSDB HTTP API 文档:http://opentsdb.net/docs/build/html/api_http/put.html

  • 注意事项
    • 对于 JSON 格式协议,TDengine 并不会自动把所有标签转成 nchar 类型,仅会将字符串转为 nchar 类型, 数值将转换为 double 类型。
    • TDengine 只接收 JSON 数组格式的字符串,即使一行数据也需要转换成数组形式。

写在最后

为了更高效地向 TDengine 写入数据,客户端程序要充分且恰当地利用以下几个因素:数据在不同表(或子表)之间的分布,即要写入数据的相邻性;单次写入的数据量;并发连接数。在单次写入中尽量只向同一张表(或子表)写入数据,每批次写入的数据量经过测试和调优,设定为一个最适合当前系统处理能力的数值,并发写入的连接数同样经过测试和调优后,设定为一个最适合当前系统处理能力的数值,以实现在当前系统中的最佳写入速度。此外,TDengine 提供的独特参数绑定写入,也是一个有助于实现高效写入的方法。

但要注意的是,如果无论怎么调节客户端程序,taosd 进程的 CPU 使用率始终都很低,那很可能需要增加 vgroup 的数量,服务端的配置同样重要。如果大家在写入操作时遇到了困难,首先可以进入 TDengine 官网-技术文档页面进行查询,如果依然无法解决,我们还有专门的社区技术人员能够为你答疑解惑。

此外,如果大家想了解 Java、Python、Go、Rust、Node.js、C#、C 不同语言的写入示例代码,也可以进入 TDengine 官网-技术文档页面查看更多详情。