10TB、20天、公有云接力:一次时序数据库 IoTDB 数据迁移的真实复盘

当机房搬迁遇上时序数据库,我们把时序文件格式 TsFile 玩成了「数据快递」。

a129b5b2adc8a828b9461322ae6150b5

一、背景:搬迁来了,数据不能丢

我们的业务场景是典型的时序数据:大量设备持续上报传感器数据,写入 IoTDB 1.3.3 集群。原集群部署在公司机房,采用 3C3D 单副本架构。

公司搬迁通知下来后,原机房需要整体停机,预计窗口 20 天。这期间站端数据采集不能停,于是我们做了一个临时决策:

核心策略

  • 搬迁期间:站端数据切到公有云临时节点,继续写入;
  • 搬迁结束后:把公有云积累的 TsFile 搬回原机房新部署的 IoTDB 集群。

听上去只是「临时存一下、搬回去」,但实际数据量到了近 10TB,任何一个环节没控制好,都会让回迁变成灾难。

二、20 天时间线

3e88921d1d8c67e8b4fd9301a4c58ea4

三、架构演进:四个阶段

ebe0eebf3517e0a12e0843ec69fa4961

四、方案对比:为什么选 TsFile 搬迁

c28bfa2d302d90909382d68a9046f46e

五、关键决策与数据

决策 1 - 单副本 3C3D,降低搬迁复杂度

原集群就是单副本,搬迁时如果改为多副本,会引入跨节点同步和一致性问题。我们保持 data_replication_factor=1 和 schema_replication_factor=1,让 node1 的数据始终回到 node1,避免分片混淆。

决策 2 - 压缩:pigz 多线程是刚需

tar cf - sequence/ unsequence/ | pigz -p 16 > /data/iotdb_migrate/node_data.tar.gz
find /data/iotdb/data/datanode/data/ -type f \( -name '*.resource' -o -name '*.mods' \) | \
    tar czf /data/iotdb_migrate/node_meta.tar.gz -T -

经验:数据包里必须包含 .resource 和 .mods。前者是索引,后者记录删除标记,漏带会让 load 重建索引或丢失删除操作。

决策 3 - 传输:xargs 并行 scp

ssh root@node "ls -1 /data/iotdb_migrate/*.tar.gz" | \
    xargs -P 6 -I {} scp root@node:{} /data/backup_from_ssd/

单线程 scp 吃不满带宽,用 xargs -P 6

决策 4 - load 参数:-tn 6、-os none、-of none

./load-tsfile.sh -h 127.0.0.1 -p 6667 -u root -pw root \
    -s /data/backup_from_ssd/tsfile_data/sequence/ \
    -tn 6 -os none -of none> /data/load_errors/load_se.log

545d65e90e30edf1cf78adb6acc52de3

六、真实踩坑

坑 1:压缩/解压时间远超预期

第一次预估时只算了网络传输时间,没把压缩、解压、load 的 I/O 开销算进去。实际上,HDD 上的解压和 load 因为随机 I/O 多,耗时比 SSD 高一个数量级。

教训:缓冲时间至少预留 50% 以上,HDD 不适合作为高性能 load 目标。

坑 2:HDD 上 cross space compaction 拖垮写入

HDD 临时集群 load 数据后,cross space compaction 一启动,随机 I/O 直接把写入压到接近停滞。后来关闭 cross space compaction、调整 schedule interval 才缓解。

enable_seq_space_compaction=true
enable_unseq_space_compaction=false
enable_cross_space_compaction=false
compaction_schedule_interval_in_ms=60000

坑 3:load 失败后的重试检查

load 不是 100% 一次性成功,失败日志和拒绝日志混在一起,人工筛查效率低。我写了一个 check_retry.sh,从拒绝日志中提取 TsFile,结合成功日志判断哪些文件需要重试。通过比对发现,load 脚本会自动重试初次加载失败的 TsFile 文件。不过比对过才知道,是不是所有的 TsFile 都被成功加载了。

grep -oP 'root\.[a-zA-Z0-9_/-]+\.tsfile' "$REJECT_LOG" | sort | uniq -c | \
    while read -r count tsfile; do
        if [ "$count" -gt 1 ]; then
            echo "[$count 次] $tsfile" >> "$NO_ONLY"
        else
            if grep "Processed success" "$LOAD_LOG" | grep -q "$tsfile"; then
                echo "$tsfile" >> "$NO_NEED_RETRY"
            else
                echo "$tsfile" >> "$NEED_RETRY"
            fi
        fi
    done

输出三份清单:重复不唯一、已成功无需重试、需要重新加载。用清单驱动重试,比逐行看日志靠谱。

坑 4:路径用相对路径导致 file not found

load 命令要求绝对路径。有一次为了省事用了相对路径,结果远端节点的工作目录不一致,报 file not found。后来所有 load 命令统一用绝对路径。

坑 5 database 未提前创建

新 SSD 集群部署后,没有提前创建与原集群一致的 database,导致 load 报 database 不存在。现在我们把「创建 database」写进了前置检查清单。

七、验证:怎么才算「搬完了」

数据迁移不能只靠「命令跑完」,必须做四层验证:

55c3f15bc00bfc03ac70c5d3bcdf3539

八、复盘与建议

875871f2ae89823f55a142680bcaf0fe

e97cecf699851f30eca062cff885ebac

九、写在最后

这次迁移让我印象最深的一点是:时序数据库的搬迁,拼的不是某一个参数,而是流程的完整度。

当你面对近 10TB 数据、400 亿+ 时序点、20 天停机窗口时,任何一个环节的遗漏都会被放大。提前写好脚本、预留缓冲时间、做好验证清单,才能让一次「数据快递」安全送达。

对于 IoTDB 的使用仍在不停的学习中,欢迎大家交流分享!

posted @ 2026-06-22 00:42  ApacheIoTDB  阅读(7)  评论(0)    收藏  举报