多模态时序数据管理
多模态时序数据管理
TimechoDB 的 OBJECT 是表模型中面向“多模态时序数据管理”的高级数据类型:它把图像、音视频、文档等非结构化对象的原始内容,与时间戳、标签及普通时序字段关联在同一条记录中,使设备运行上下文和现场多媒体证据能够统一写入、检索与管理。
1. OBJECT 数据类型
1.1 数据类型定义
OBJECT 是表模型中的大对象数据类型,自 V2.0.8.1 起支持。原始二进制内容以独立文件保存。其写放大系数恒为 1,空间放大低,采用 merge & release on write。
OBJECT 适合需要通过分段方式上传的较大对象文件。若数据是小数、短文本、枚举或需要高频表达式运算,应优先使用普通标量类型。
关于 OBJECT 与 BLOB 的具体区别,请参见数据类型。
1.2 类型兼容规则
OBJECT 列支持的写入数据类型如下:
| 列数据类型 | 支持的写入数据类型 |
|---|---|
| OBJECT | OBJECT |
OBJECT 列仅接受 OBJECT 类型的值,不支持直接写入 STRING、TEXT 或 BLOB 值;写入不兼容的数据类型时,系统会报错。因此,SQL 写入需使用 to_object(...) 构造 OBJECT 值,客户端写入需使用相应的 OBJECT 写入接口。
1.3 存储与访问
OBJECT 的原始二进制内容存放在 ${data_dir}/object 目录下。为避免单个对象过大导致单次写入请求过大,可以将对象拆分后按顺序分段写入。
直接查询 OBJECT 列时,返回形如 (Object) 5 B 的对象大小摘要。需要获取原始内容时,使用 READ_OBJECT 函数读取,返回类型为 BLOB;也可以指定偏移量和长度,分段读取对象内容。
1.4 相关配置
OBJECT 相关配置及默认值如下,可根据需要调整。其中,restrict_object_limit 仅允许在服务首次启动前修改。
| 配置项 | 说明 | 类型 | 默认值 | 生效方式 |
|---|---|---|---|---|
max_object_file_size_in_byte | 单个对象文件的最大尺寸,单位为字节,V2.0.8.1 起支持 | long | 4294967296(4 GiB) | 热加载 |
restrict_object_limit | 是否启用 OBJECT 相关名称的文件系统路径限制,V2.0.8.1 起支持 | boolean | false | 仅允许在第一次启动服务前修改 |
max_object_file_size_in_byte 的实际生产值应结合对象文件大小、磁盘 IO、网络传输、备份窗口和恢复目标综合评估。
当 restrict_object_limit=true 且表中包含 OBJECT 列时,需注意:
TAG 列的值、表名和字段名禁止使用
.或..,且不得包含./或.字符,否则元数据创建失败。名称包含文件系统不支持的字符时,数据写入会报错。若底层文件系统不区分大小写,
d1和D1等设备标识可能映射至相同文件位置,导致对象文件互相覆盖并造成数据错误。对象文件的路径格式如下:
${dataregionid}/${tablename}/${tag1}/${tag2}/.../${field}/${timestamp}.bin1.5 删除失败审计
FAILED_TTL_DELETION 自 V2.0.11.1 起支持,用于记录 TTL 删除失败事件。该事件仅在失败时记录,成功时不记录。
auditable_control_event_type 的默认白名单包含 FAILED_TTL_DELETION。需记录该事件时,应开启安全审计并确保白名单中包含该项;从白名单移除该项可关闭此类事件记录。安全审计的 enable_audit_log 默认为 false。
失败场景和日志格式如下:
| 失败场景 | 触发条件 | 日志格式 | 日志说明 | 日志数量 |
|---|---|---|---|---|
| Object 文件扫描失败 | 系统扫描并删除过期 Object 文件时,因磁盘 I/O 错误、权限不足等异常导致扫描失败。 | TTL object scan failed: errors=[ClassName1 xN1(msg1),ClassName2 xN2(msg2)] | 系统按表汇总单次扫描过程中发生的异常。同一类型的异常合并记录其出现次数,并保留首次出现的异常消息。 | 每次扫描中,每个发生异常的表产生 1 条审计日志。 |
| TTL 检查启动失败 | Object 文件扫描在开始逐表检查前发生异常,或 Settle Compaction 在选择任务时发生异常,导致本轮 TTL 检查未能启动。 | TTL check failed to start: {msg} error=ClassName(exceptionMsg) | TTL 检查在确定待处理表之前失败,日志不记录表信息,仅记录失败阶段及异常原因。 | 每次检查启动失败产生 1 条审计日志。 |
| Settle Compaction 执行失败 | Settle Compaction 执行结束后返回失败结果(isSuccess=false)。 | TTL settle compaction failed: error=... | 日志记录 Settle Compaction 的失败原因,以及本次任务涉及的 TTL 表;表名由 Selector 在扫描设备时收集。 | 每次 Settle Compaction 执行失败时,每个涉及 TTL 的表产生 1 条审计日志。 |
表模型审计日志存储位置为 __audit.audit_log。审计的通用配置和查询语法请参见安全审计。
2. 数据建模
2.1 使用准备
执行示例时,请通过表模型会话连接。执行建库、建表、写入及查询操作的用户需具有相应权限,具体请参见权限管理。
本文 SQL 示例使用数据库 database1、表 table1 和 OBJECT 测点列 s1,请在测试环境中新建示例数据库和表,并按顺序执行。客户端连接方式请参见命令行工具。
2.2 创建包含 OBJECT 列的表
表模型使用 TAG 列标识设备,使用 FIELD 列存放随时间变化的测点值。OBJECT 列应定义为 FIELD,TAG 和 ATTRIBUTE 列的数据类型为 STRING,TIME 列的数据类型为 TIMESTAMP。
创建数据库,并在建表时定义 OBJECT 测点列 s1:
CREATE DATABASE database1;
USE database1;
CREATE TABLE table1 (
time TIMESTAMP TIME,
region STRING TAG,
plant_id STRING TAG,
device_id STRING TAG,
model_id STRING ATTRIBUTE,
maintenance STRING ATTRIBUTE,
temperature FLOAT FIELD,
humidity FLOAT FIELD,
status Boolean FIELD,
arrival_time TIMESTAMP FIELD,
s1 OBJECT FIELD COMMENT 'object类型'
);表结构沿用示例数据中的 table1,增加 s1 用于存储对象内容。下文写入示例为 region、plant_id、device_id 三个 TAG 列分别指定 '北京'、'1001'、'tag1'。
数据保留时间:
建表时未指定 TTL,则采用数据库的 TTL,也可以在建表时单独设置表的 TTL。TTL 根据数据点时间判断是否过期,过期数据不可查询;过期的 OBJECT 文件由系统扫描并删除。具体设置方式请参见数据保留时间。
2.3 在已有表中增加 OBJECT 列
对于已有表,可以通过 ALTER TABLE 增加 OBJECT 测点列:
ALTER TABLE table1
ADD COLUMN IF NOT EXISTS s1 OBJECT FIELD COMMENT 'object类型';关于表结构和列类别的完整说明,请参见表管理。
3. 数据写入
3.1 写入函数
自 V2.0.8 起,支持使用 to_object 函数构造 OBJECT 写入值。为避免单个对象过大导致单次请求过大,可以将对象拆分后按顺序写入。
语法:
to_object(isEOF, offset, content)参数:
| 参数 | 数据类型 | 说明 |
|---|---|---|
isEOF | BOOLEAN | 本次写入内容是否为对象的最后一部分 |
offset | INT64 | 本次内容在完整对象中的起始偏移量,单位为字节 |
content | 十六进制格式 | 本次写入的二进制内容,使用 X'...' 表示 |
SQL 基本形式:
INSERT INTO tableName(time, columnName)
VALUES (timeValue, to_object(isEOF, offset, content));3.2 单段写入
向同一条记录写入设备标签和对象内容:
INSERT INTO table1(time, region, plant_id, device_id, s1)
VALUES (now(), '北京', '1001', 'tag1', to_object(true, 0, X'696F746462'));其中,true 表示该段为最后一段,0 表示从对象起始位置写入。示例内容为 5 字节的 0x696f746462,用于演示二进制读写。
3.3 分段写入
将相同内容拆为 696F、7464、62 三段,写入时间戳 1:
-- 第一段:写入 2 字节,尚未结束。
INSERT INTO table1(time, region, plant_id, device_id, s1)
VALUES (1, '北京', '1001', 'tag1', to_object(false, 0, X'696F'));
-- 第二段:从偏移量 2 开始,继续写入 2 字节。
INSERT INTO table1(time, region, plant_id, device_id, s1)
VALUES (1, '北京', '1001', 'tag1', to_object(false, 2, X'7464'));
-- 最后一段:从偏移量 4 开始,写入剩余 1 字节。
INSERT INTO table1(time, region, plant_id, device_id, s1)
VALUES (1, '北京', '1001', 'tag1', to_object(true, 4, X'62'));所有分段使用相同的时间戳、TAG 值和 OBJECT 列,写入完成后的内容为 0x696f746462。
注意:
对象仅写入部分片段时,查询该值返回
null;完整写入后才能查询到对象。本次写入的
offset必须等于已经写入的对象大小,否则写入报错。已写入部分数据后,如果再次以
offset=0写入,会清除先前已写入的部分并重新开始。续写时需使用正确的偏移量。Windows 环境写入 OBJECT 数据时,所有 TAG 字段必须显式赋值,否则可能因创建包含 NUL 的目录失败而触发
741异常。INSERT INTO QUERY目前不支持 Object 类型。
其他写入与更新语法请参见写入&更新。
4. 数据查询
4.1 查询对象摘要
以下查询以第 3.3 节完成分段写入的数据为例。直接查询 OBJECT 列,返回对象大小摘要:
SELECT s1
FROM table1
WHERE device_id = 'tag1' AND time = 1;示例结果:
+------------+
| s1|
+------------+
|(Object) 5 B|
+------------+4.2 读取原始内容
READ_OBJECT 自 V2.0.8 起支持,用于读取 OBJECT 的二进制内容,返回类型为 BLOB。
语法:
READ_OBJECT(object [, offset, length])参数:
| 参数 | 类型 | 说明 |
|---|---|---|
object | OBJECT | 必填,要读取的对象 |
offset | INT64 | 可选,读取偏移量,默认为 0。小于 0 或大于等于完整对象长度时抛出异常 |
length | INT64 | 可选,读取长度,默认为完整对象长度。大于 2^31 - 1 时报错;大于从偏移量起的剩余长度时返回剩余内容;小于 0 时读取从偏移量开始的全部剩余内容 |
读取完整内容:
SELECT READ_OBJECT(s1)
FROM table1
WHERE device_id = 'tag1' AND time = 1;示例结果:
+------------+
| _col0|
+------------+
|0x696f746462|
+------------+读取前 3 字节:
SELECT READ_OBJECT(s1, 0, 3)
FROM table1
WHERE device_id = 'tag1' AND time = 1;示例结果:
+--------+
| _col0|
+--------+
|0x696f74|
+--------+完整读取结果应为 0x696f746462,可据此核对第 3.3 节分段写入的结果。
读取较大对象时,可以通过 offset 和 length 分段读取,并遵守单次读取长度限制。
4.3 长度、类型转换与空值填充
获取对象长度
自 V2.0.9.1 起支持[length](../SQL-Manual/Basis-Function_timecho.md#_7-3-二进制基础函数) 函数用于获取 OBJECT 二进制内容的字节大小,返回类型为 INT32。
length(input)类型转换
自 V2.0.8.1 起支持使用 [CAST](../SQL-Manual/Basis-Function_timecho.md#_9-1-转换函数) 将 OBJECT 转换为 STRING:
SELECT CAST(s1 AS STRING)
FROM table1;空值填充
OBJECT 类型支持的填充方法如下:
| 填充方法 | 支持情况 |
|---|---|
PREVIOUS | 支持,使用该列前一个非空值填充 |
NEXT | 自 V2.0.11.1 起支持,使用该列后一个非空值填充 |
LINEAR | 不支持 |
CONSTANT | 不支持 |
当指定的填充方法不支持 OBJECT 类型时,OBJECT 列保持原样,不进行填充,也不因此抛出异常。
填充方法的参数与使用示例,请参见FILL 子句。
5. 原生接口
5.1 Java 原生接口
Java 表模型通过 ITableSession.insert(Tablet tablet) 写入 Tablet 中的数据。自 V2.0.8 起,该接口支持 OBJECT 分段写入。分段写入 OBJECT 时,使用以下方法向 Tablet 的 OBJECT 列填入对象分段:
void addValue(int rowIndex, int columnIndex, boolean isEOF, long offset, byte[] content)| 参数 | 说明 |
|---|---|
rowIndex | Tablet 中的行位置 |
columnIndex | Tablet 中的列位置 |
isEOF | 是否为对象的最后一个分段 |
offset | 本段在完整对象中的起始偏移量 |
content | 本次写入的字节内容 |
多个分段的 byte[] 总长度必须等于原始对象大小,否则会导致写入的数据大小不正确。分段需按顺序提交,offset 与 isEOF 的含义与 SQL 写入一致。
写入调用示意
向 Tablet 的 OBJECT 列填入对象内容后,调用 insert 提交写入:
Tablet tablet = new Tablet(...);
tablet.addValue(rowIndex, objectColumnIndex, true, 0, content);
session.insert(tablet);其中,rowIndex、objectColumnIndex 和 content 分别为行号、OBJECT 列号和本次写入的字节内容;true, 0 表示从起始位置一次写完对象。new Tablet(...) 省略了表结构等构造参数。
直接查询 OBJECT 列时,Field.getStringValue、Field.getObjectValue、SessionDataSet.DataIterator.getObject 和 SessionDataSet.DataIterator.getString 返回形如 (Object) XX.XX KB 的字符串摘要。
关于客户端依赖、会话创建及结果集读取,请参见Java 原生接口。
5.2 Python 原生接口
自 V2.0.8.3 起,Python 客户端在 Tablet 批量写入和 Session 值序列化中支持 TSDataType.OBJECT。
5.2.1 OBJECT 相关接口
| 接口 | 参数 | 说明与返回值 |
|---|---|---|
encode_object_cell | is_eof: bool, offset: int, content: bytes | 将一个 OBJECT 单元格编码为线格式,返回 bytes |
decode_object_cell | cell: bytes,长度至少为 9 字节 | 解析已编码的 OBJECT 单元格,返回 (is_eof, offset, payload) |
Tablet.add_value_object | row_index: int, column_index: int, is_eof: bool, offset: int, content: bytes | 在指定行、列填入 OBJECT 分段,返回 None |
Tablet.add_value_object_by_name | column_name: str, row_index: int, is_eof: bool, offset: int, content: bytes | 按列名填入 OBJECT 分段,返回 None |
NumpyTablet.add_value_object | 与 Tablet.add_value_object 相同 | 向 NumpyTablet 的 OBJECT 列填入分段,列数据为 ndarray,返回 None |
Field.get_object_value | data_type: TSDataType | 当目标类型为 OBJECT 时,将查询值按 UTF-8 解码为 str |
Field.get_string_value | 无 | 将 OBJECT 查询值按 UTF-8 解码为 str |
Field.get_binary_value | 无 | 获取 TEXT、STRING、BLOB 的二进制内容,返回 bytes 或 None;直接对 OBJECT 列调用会报错 |
直接查询 OBJECT 列得到的是对象大小摘要。需要读取原始字节时,在查询中使用 READ_OBJECT,再通过 Field.get_binary_value() 获取 BLOB 结果中的字节内容。
5.2.2 OBJECT 单元格编码
OBJECT 单元格的线格式如下:
|[eof 1B]|[offset 8B BE]|[payload]|eof占 1 字节,表示是否为对象的最后一段。offset占 8 字节,采用大端序,表示本段在对象中的起始偏移量。payload为本段的字节内容。
encode_object_cell(is_eof, offset, content) 用于生成上述编码。对已编码的 OBJECT 单元格 raw_cell,可按以下方式解析:
from iotdb.utils.object_column import decode_object_cell
eof, off, body = decode_object_cell(bytes(raw_cell))返回值为 (is_eof: bool, offset: int, payload: bytes)。
5.2.3 写入与读取示例
以下示例沿用 Python 原生接口页中的 test_py_object_e2e.obj_tbl,展示 Tablet、NumpyTablet、分段写入及原始字节读回校验。代码使用已建立连接的表模型会话 table_session,请在新建的示例表上执行。客户端安装和会话创建请参见Python 原生接口。
import numpy as np
from iotdb.utils.IoTDBConstants import TSDataType
from iotdb.utils.Tablet import Tablet, ColumnType
from iotdb.utils.NumpyTablet import NumpyTablet
db = "test_py_object_e2e"
table = "obj_tbl"
table_session.execute_non_query_statement(f"create database if not exists {db}")
table_session.execute_non_query_statement(f"use {db}")
table_session.execute_non_query_statement(
f"create table {table}("
"device STRING TAG, temp FLOAT FIELD, f1 OBJECT FIELD, f2 OBJECT FIELD)"
)
column_names = ["device", "temp", "f1", "f2"]
data_types = [
TSDataType.STRING,
TSDataType.FLOAT,
TSDataType.OBJECT,
TSDataType.OBJECT,
]
column_types = [
ColumnType.TAG,
ColumnType.FIELD,
ColumnType.FIELD,
ColumnType.FIELD,
]
timestamps = [100, 200]
values = [
["d1", 1.5, None, None],
["d1", 2.5, None, None],
]
tablet = Tablet(
table, column_names, data_types, values, timestamps, column_types
)
tablet.add_value_object(0, 2, True, 0, b"first-row-obj")
# 整对象单段写入:is_eof=True 且 offset=0;分段续写需满足服务端 offset/长度校验
tablet.add_value_object_by_name("f2", 0, True, 0, b"seg")
tablet.add_value_object(1, 2, True, 0, b"second-f1")
tablet.add_value_object(1, 3, True, 0, b"second-f2")
table_session.insert(tablet)
ts_arr = np.array([300, 400], dtype=TSDataType.INT64.np_dtype())
np_vals = [
np.array(["d1", "d1"]),
np.array([1.0, 2.0], dtype=np.float32),
np.array([None, None], dtype=object),
np.array([None, None], dtype=object),
]
np_tab = NumpyTablet(
table, column_names, data_types, np_vals, ts_arr, column_types=column_types
)
np_tab.add_value_object(0, 2, True, 0, b"np-r0-f1")
np_tab.add_value_object(0, 3, True, 0, b"np-r0-f2")
np_tab.add_value_object(1, 2, True, 0, b"np-r1-f1")
np_tab.add_value_object(1, 3, True, 0, b"np-r1-f2")
table_session.insert(np_tab)
# 分段 OBJECT:先 is_eof=False(续传),再 is_eof=True(末段);offset 为已写入字节长度
chunk0 = bytes((i % 256) for i in range(512))
chunk1 = b"\xab" * 64
expected_segmented = chunk0 + chunk1
seg1 = Tablet(
table,
column_names,
data_types,
[["d1", 3.0, None, None]],
[500],
column_types,
)
seg1.add_value_object(0, 2, False, 0, chunk0)
seg1.add_value_object(0, 3, True, 0, b"f2-seg")
table_session.insert(seg1)
seg2 = Tablet(
table,
column_names,
data_types,
[["d1", 3.0, None, None]],
[500],
column_types,
)
seg2.add_value_object(0, 2, True, 512, chunk1)
seg2.add_value_object(0, 3, True, 0, b"f2-seg")
table_session.insert(seg2)
with table_session.execute_query_statement(
f"select read_object(f1) from {table} where time = 500"
) as ds:
assert ds.has_next()
row = ds.next()
blob = row.get_fields()[0].get_binary_value()
assert blob == expected_segmented
assert not ds.has_next()分段写入时,后续分段的 offset 等于已写入字节数,最后一段设置 is_eof=True;全部分段的总长度须与完整对象大小一致。
直接查询 OBJECT 列时,可以通过 Field.get_string_value() 或 Field.get_object_value(TSDataType.OBJECT) 获取字符串表示:
with table_session.execute_query_statement(
f"select device, temp, f1, f2 from {table} order by time"
) as ds:
while ds.has_next():
row = ds.next()
fields = row.get_fields()
for j in (2, 3):
fields[j].get_string_value()
fields[j].get_object_value(TSDataType.OBJECT)5.3 C 与 C++ 原生接口
当前 SessionC 不提供 ts_tablet_add_value_object,OBJECT 写入请使用 C++ Session API。C++ 会话与通用 Tablet 接口的使用方式请参见C++ 原生接口。
6. 数据导入与导出
6.1 包含 OBJECT 数据的 TsFile 导入
自 V2.0.9.2 起,表模型 import-data 的 TsFile 导入支持 OBJECT 数据。导入时,需同时准备 TsFile 和关联的对象文件。
不指定对象目录时,工具默认识别 TsFile 同名子目录下的对象文件:
/data/import/
├── sensor_v1.tsfile
└── sensor_v1/
├── regionID/tableName/tag1/tag2/field/timestamp1.bin
└── regionID/tableName/tag1/tag2/field/timestamp2.bin以下命令在安装目录下执行,目标数据库为 database1。导入前需准备好 TsFile 及关联的对象文件:
tools/import-data.sh -sql_dialect table -ft tsfile \
-s /data/import/sensor_v1.tsfile -db database1 -os none -of none对象文件位于外部目录时,通过 -o(--object-file-paths)指定对象文件的存储根目录。该参数自 V2.0.9.2 起支持。例如:
tools/import-data.sh -sql_dialect table -ft tsfile \
-s /data/import/sensor_v1.tsfile -db database1 \
-o /mnt/object_storage/ -os none -of none/mnt/object_storage/ 下应按 regionID/tableName/tag1/tag2/field/timestamp.bin 等层级准备关联的对象文件。
上述示例显式设置 -os none 和 -of none,分别指定导入成功和失败后的源文件处理方式,不删除或移动源文件。Windows 对应入口为 tools\windows\import-data.bat。完整参数请参见数据导入。
6.2 通过 TsFileBackup 导出
自 V2.0.9.2 起,tsfile-backup.sh/bat 支持将包含 OBJECT 的数据导出为 TsFile 和关联的对象目录。该工具基于 PIPE 框架生成并发送 CREATE PIPE SQL。
使用前,需联系天谋团队获取 tsfile-remote-sink-<version>-jar-with-dependencies.jar,并放至服务端可访问的路径,例如所有 DataNode 主机。
以下示例通过 SCP 导出到远程服务器,在安装目录下执行:
tools/tsfile-backup.sh -sql_dialect table \
-db database1 -table table1 -t /remote/archive/ \
-th 192.168.1.100 -tu backup_user -tpw将远程主机、用户和目录替换为实际值;-tpw 不跟值时,以隐藏输入方式提供远程主机密码。Windows 对应入口为 tools\windows\tsfile-backup.bat。
OBJECT 导出的相关参数如下:
| 参数 | 说明 |
|---|---|
--plugin_jar | 指定 Pipe 插件 JAR 包路径 |
--rate_limit | 发送速率限制,单位为字节/秒 |
--object-parallelism | OBJECT 文件发送最大并行度 |
--object-batch-size | 限制每个对象文件上传批次的总字节数,用于控制内存占用和单次 SCP 传输大小 |
需要指定插件 JAR 路径时,可在命令中添加 --plugin_jar /local/lib/tsfile-remote-sink-<version>-jar-with-dependencies.jar。
SCP 导出 OBJECT 时,若出现握手异常、连接失败或 Pipe 频繁启停,可适当调低 --object-parallelism,或按需调大目标机 SSH 的 MaxStartups,再执行 sshd reload 或 sshd restart 使配置生效。
数据库连接、时间范围等通用参数请参见数据导出。
6.3 通过 Pipe 导出
自 V2.0.9.2 起,表模型 Pipe 支持以下 OBJECT 数据导出方式:
| 方式 | 说明 |
|---|---|
| 本地导出 | 使用内置的 tsfile-local-sink,导出到数据库服务器所在的本地文件系统 |
| 远程传输 | 使用 tsfile-remote-sink JAR 包注册插件后,通过 SSH/SCP 发送到远程服务器 |
下面的示例将 database1.table1 导出到服务器本地目录:
CREATE PIPE tsfile_export_local
WITH SOURCE (
'source' = 'iotdb-source',
'database-name' = 'database1',
'table-name' = 'table1'
)
WITH PROCESSOR (
'processor' = 'do-nothing-processor'
)
WITH SINK (
'sink' = 'tsfile-local-sink',
'sink.local.target-path' = '/data/backup/export_2024',
'sink.rate-limit-bytes-per-second' = '10485760'
);示例设置发送速率上限为 10485760 字节/秒。导出目录中包含 TsFile 及其同名对象子目录,目录结构见第 6.1 节。
查看任务状态:
SHOW PIPE tsfile_export_local;远程 SCP 导出
联系天谋团队获取 tsfile-remote-sink-<version>-jar-with-dependencies.jar,并放至服务端可访问的路径,例如所有 DataNode 主机。先注册插件:
CREATE PIPEPLUGIN tsfile_remote_sink
AS 'org.apache.iotdb.pipe.plugin.sink.tsfile.PipeTsFileRemoteSink'
USING URI 'file:///path/to/tsfile-remote-sink-<version>-jar-with-dependencies.jar';再创建远程导出任务:
CREATE PIPE tsfile_export_scp
WITH SOURCE (
'source' = 'iotdb-source',
'database-name' = 'database1',
'table-name' = 'table1'
)
WITH PROCESSOR (
'processor' = 'do-nothing-processor'
)
WITH SINK (
'sink' = 'tsfile_remote_sink',
'sink.file-mode' = 'scp',
'sink.scp.host' = '192.168.1.100',
'sink.scp.port' = '22',
'sink.scp.user' = 'backup_user',
'sink.scp.password' = '<远程主机密码>',
'sink.scp.remote-path' = '/remote/archive/',
'sink.rate-limit-bytes-per-second' = '10485760'
);将插件路径、远程主机、用户名、密码和目录替换为实际值。Pipe 中的 sink 使用注册时指定的插件名 tsfile_remote_sink。
远程传输的参数如下:
| 参数 | 说明 | 默认值 |
|---|---|---|
sink.scp.host | 远程主机 IP,必填 | 无 |
sink.scp.port | 远程 SSH 端口 | 22 |
sink.scp.user | 远程 SSH 用户,必填 | 无 |
sink.scp.password | 远程 SSH 密码,必填 | 无 |
sink.scp.remote-path | 远程目标目录,必填 | 无 |
sink.rate-limit-bytes-per-second | 发送速率限制,单位为字节/秒;值小于等于 0 时不限速 | 0 |
sink.scp.object-parallelism | OBJECT 文件发送最大并行度 | min(cpu/4, 16) |
sink.scp.object-batch-size-bytes | 单次异步线程发送的最大 OBJECT 文件大小,参数说明标注单位为 MB | 200 |
sink.scp.object-batch-size-bytes 的参数名与说明中的单位存在差异,实际取值单位待核实;本页示例未设置该参数。
任务管理
-- 查看全部任务
SHOW PIPES;
-- 查看指定任务
SHOW PIPE tsfile_export_scp;
-- 停止、启动任务
STOP PIPE tsfile_export_scp;
START PIPE tsfile_export_scp;
-- 删除任务
DROP PIPE IF EXISTS tsfile_export_scp;修改任务参数的语法如下:
ALTER PIPE [IF EXISTS] <PipeId>
MODIFY SOURCE (...);Pipe 的其他 source、processor、sink 参数及任务管理用法,请参见数据同步和SQL 数据同步。
7. 常见问题
| 现象 | 说明与处理方式 |
|---|---|
查询 OBJECT 列时只显示 (Object) ... | 默认查询返回大小摘要;使用 READ_OBJECT 读取二进制内容 |
分段写入过程中查询到 null | 检查分段是否全部写入,以及最后一段是否设置 isEOF=true |
| 续写报偏移量错误 | 检查本次 offset 是否等于已写入字节数;以 0 重新写入会清除之前的部分内容 |
| Windows 写入触发创建 NUL 目录失败 | 检查是否显式赋值全部 TAG 字段 |
使用 READ_OBJECT 读取时报偏移量或长度错误 | 检查偏移量范围,并确认单次读取长度不超过 2^31 - 1 |
| SCP 导出出现握手异常、连接失败或 Pipe 频繁启停 | 按数据同步或导出工具文档适当调低对象发送并行度,或调整目标机 SSH 的 MaxStartups 并使配置生效 |