14 KiB
DataX TDengineWriter
简体中文| English
1 快速介绍
TDengineWriter插件实现了写入数据到TDengine数据库功能。可用于离线同步其它数据库的数据到TDengine。
2 实现原理
TDengineWriter 通过 DataX 框架获取 Reader生成的协议数据,根据reader的类型解析数据。目前有两种写入方式:
-
对于OpenTSDBReader, TDengineWriter通过JNI方式调用TDengine客户端库文件(taos.lib或taos.dll)中的方法,使用schemaless的方式写入。
-
对于其它数据源,会根据配置生成SQL语句, 通过taos-jdbcdriver批量写入。
这样区分的原因是OpenTSDBReader将opentsdb的数据统一读取为json字符串,Writer端接收到的数据只有1列。而其它Reader插件一般会把数据放在不同列。
3 功能说明
3.1 从OpenTSDB到TDengine
3.1.1 配置样例
{
"job": {
"content": [
{
"reader": {
"name": "opentsdbreader",
"parameter": {
"endpoint": "http://192.168.1.180:4242",
"column": [
"weather_temperature"
],
"beginDateTime": "2021-01-01 00:00:00",
"endDateTime": "2021-01-01 01:00:00"
}
},
"writer": {
"name": "tdenginewriter",
"parameter": {
"host": "192.168.1.180",
"port": 6030,
"dbname": "test",
"user": "root",
"password": "taosdata"
}
}
}
],
"setting": {
"speed": {
"channel": 1
}
}
}
}
3.1.2 参数说明
参数 | 描述 | 是否必选 | 默认值 |
---|---|---|---|
host | TDengine实例的host | 是 | 无 |
port | TDengine实例的port | 是 | 无 |
user | TDengine实例的用户名 | 否 | root |
password | TDengine实例的密码 | 否 | taosdata |
dbname | 目的数据库的名称 | 是 | 无 |
batchSize | 每次批量插入多少记录 | 否 | 1 |
3.1.3 类型转换
目前,由于OpenTSDBReader将opentsdb的数据统一读取为json字符串,TDengineWriter 在做Opentsdb到TDengine的迁移时,按照以下类型进行处理:
OpenTSDB数据类型 | DataX 内部类型 | TDengine 数据类型 |
---|---|---|
timestamp | Date | timestamp |
Integer(value) | Double | double |
Float(value) | Double | double |
String(value) | String | binary |
Integer(tag) | String | binary |
Float(tag) | String | binary |
String(tag) | String | binary |
3.2 从MongoDB到TDengine
3.2.1 配置样例
{
"job": {
"setting": {
"speed": {
"channel": 2
}
},
"content": [
{
"reader": {
"name": "mongodbreader",
"parameter": {
"address": [
"127.0.0.1:27017"
],
"userName": "user",
"mechanism": "SCRAM-SHA-1",
"userPassword": "password",
"authDb": "admin",
"dbName": "test",
"collectionName": "stock",
"column": [
{
"name": "stockID",
"type": "string"
},
{
"name": "tradeTime",
"type": "date"
},
{
"name": "lastPrice",
"type": "double"
},
{
"name": "askPrice1",
"type": "double"
},
{
"name": "bidPrice1",
"type": "double"
},
{
"name": "volume",
"type": "int"
}
]
}
},
"writer": {
"name": "tdenginewriter",
"parameter": {
"host": "localhost",
"port": 6030,
"dbname": "test",
"user": "root",
"password": "taosdata",
"stable": "stock",
"tagColumn": {
"industry": "energy",
"stockID": 0
},
"fieldColumn": {
"lastPrice": 2,
"askPrice1": 3,
"bidPrice1": 4,
"volume": 5
},
"timestampColumn": {
"tradeTime": 1
}
}
}
}
]
}
}
注:本配置的writer部分同样适用于关系型数据库
3.2.2 参数说明
参数 | 描述 | 是否必选 | 默认值 | 备注 |
---|---|---|---|---|
host | TDengine实例的host | 是 | 无 | |
port | TDengine实例的port | 是 | 无 | |
user | TDengine实例的用户名 | 否 | root | |
password | TDengine实例的密码 | 否 | taosdata | |
dbname | 目的数据库的名称 | 是 | 无 | |
batchSize | 每次批量插入多少记录 | 否 | 1000 | |
stable | 目标超级表的名称 | 是(OpenTSDB除外) | 无 | |
tagColumn | 标签列的列名和位置 | 否 | 无 | 位置索引均从0开始 |
fieldColumn | 字段列的列名和位置 | 否 | 无 | |
timestampColumn | 时间戳列的列名和位置 | 否 | 无 | 时间戳列只能有一个 |
3.2.3 自动建表规则
3.2.3.1 超级表创建规则
如果配置了tagColumn、 fieldColumn和timestampColumn将会在插入第一条数据前,自动创建超级表。
数据列的类型从第1条记录自动推断, 标签列默认类型为NCHAR(64)
, 比如示例配置,可能生成以下建表语句:
CREATE STABLE IF NOT EXISTS market_snapshot (
tadetime TIMESTAMP,
lastprice DOUBLE,
askprice1 DOUBLE,
bidprice1 DOUBLE,
volume INT
)
TAGS(
industry NCHAR(64),
stockID NCHAR(64)
);
3.2.3.2 子表创建规则
子表结构与超级表相同,子表表名生成规则:
- 将标签的value 组合成为如下的字符串:
tag_value1!tag_value2!tag_value3
。 - 计算该字符串的 MD5 散列值 "md5_val"。
- "t_md5val"作为子表名。其中的 "t" 是固定的前缀。
3.2.4 用户提前建表
如果你已经创建好目标超级表,那么tagColumn、 fieldColumn和timestampColumn三个字段均可省略, 插件将通过执行通过describe stableName
获取表结构的信息。
此时要求接收到的Record中Column的顺序和执行describe stableName
返回的列顺序相同, 比如通过describe stableName
返回以下内容:
Field | Type | Length | Note |
=================================================================================
ts | TIMESTAMP | 8 | |
current | DOUBLE | 8 | |
location | BINARY | 10 | TAG |
那么插件收到的数据第1列必须代表时间戳,第2列必须代表电流,第3列必须代表位置。
3.2.5 注意事项
- tagColumn、 fieldColumn和timestampColumn三个字段用于描述目标表的结构信息,这三个配置字段必须同时存在或同时省略。
- 如果存在以上三个配置,且目标表也已经存在,则两者必须一致。一致性由用户自己保证,插件不做检查。不一致可能会导致插入失败或插入数据错乱。
3.2.6 类型转换
MongoDB 数据类型 | DataX 内部类型 | TDengine 数据类型 |
---|---|---|
int, Long | Long | BIGINT |
double | Double | DOUBLE |
string, array | String | NCHAR(64) |
date | Date | TIMESTAMP |
boolean | Boolean | BOOL |
bytes | Bytes | BINARY |
3.3 从关系型数据库到TDengine
writer部分的配置规则和上述MongoDB的示例是一样的,这里给出一个MySQL的示例。
3.3.1 MySQL中表结构
CREATE TABLE IF NOT EXISTS weather(
station varchar(100),
latitude DOUBLE,
longtitude DOUBLE,
`date` DATE,
TMAX int,
TMIN int
)
3.3.2 配置文件示例
{
"job": {
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "root",
"password": "passw0rd",
"column": [
"*"
],
"splitPk": "station",
"connection": [
{
"table": [
"weather"
],
"jdbcUrl": [
"jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8"
]
}
]
}
},
"writer": {
"name": "tdenginewriter",
"parameter": {
"host": "127.0.0.1",
"port": 6030,
"dbname": "test",
"user": "root",
"password": "taosdata",
"batchSize": 1000,
"stable": "weather",
"tagColumn": {
"station": 0
},
"fieldColumn": {
"latitude": 1,
"longtitude": 2,
"tmax": 4,
"tmin": 5
},
"timestampColumn":{
"date": 3
}
}
}
}
],
"setting": {
"speed": {
"channel": 1
}
}
}
}
4 性能报告
4.1 环境准备
4.1.1 数据特征
建表语句:
单行记录类似于:
4.1.2 机器参数
-
执行DataX的机器参数为:
- cpu:
- mem:
- net: 千兆双网卡
- disc: DataX 数据不落磁盘,不统计此项
-
TDengine数据库机器参数为:
- cpu:
- mem:
- net: 千兆双网卡
- disc:
4.1.3 DataX jvm 参数
-Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError
4.2 测试报告
4.2.1 单表测试报告
通道数 | DataX速度(Rec/s) | DataX流量(MB/s) | DataX机器网卡流出流量(MB/s) | DataX机器运行负载 | DB网卡进入流量(MB/s) | DB运行负载 | DB TPS |
---|---|---|---|---|---|---|---|
1 | |||||||
4 | |||||||
8 | |||||||
16 | |||||||
32 |
说明:
- 这里的单表,主键类型为 bigint(20),自增。
- batchSize 和 通道个数,对性能影响较大。
- 16通道,4096批量提交时,出现 full gc 2次。
4.2.4 性能测试小结
5 约束限制
- 本插件自动创建超级表时NCHAR类型的长度固定为64,对于包含长度大于64的字符串的数据源,将不支持。
- 标签列不能包含null值,如果包含会被过滤掉。
FAQ
如何选取要同步的数据的范围?
数据范围的选取在Reader插件端配置,对于不同的Reader插件配置方法往往不同。比如对于mysqlreader, 可以用sql语句指定数据范围。对于opentsdbreader, 用beginDateTime和endDateTime两个配置项指定数据范围。
如何一次导入多张源表?
如果Reader插件支持一次读多张表,Writer插件就能一次导入多张表。如果Reader不支持多多张表,可以建多个job,分别导入。Writer插件只负责写数据。
一张源表导入之后对应TDengine中多少张表?
这是由tagColumn决定的,如果所有tag列的值都相同,那么目标表只有一个。源表有多少不同的tag组合,目标超级表就有多少子表。
源表和目标表的字段顺序一致吗?
TDengine要求每个表第一列是时间戳列,后边是普通字段,最后是标签列。如果源表不是这个顺序,插件在自动建表时会自动调整。
插件如何确定各列的数据类型?
根据收到的第一批数据自动推断各列的类型。
为什么插入10年前的数据会抛异常TDengine ERROR (2350): failed to execute batch bind
?
因为创建数据库的时候,默认保留10年的数据。可以手动指定要保留多长时间的数据,比如:CREATE DATABASE power KEEP 36500;
。