10TB、20天、公有云接力:一次时序数据库 IoTDB 数据迁移的真实复盘
当机房搬迁遇上时序数据库,我们把时序文件格式 TsFile 玩成了「数据快递」。

一、背景:搬迁来了,数据不能丢
我们的业务场景是典型的时序数据:大量设备持续上报传感器数据,写入 IoTDB 1.3.3 集群。原集群部署在公司机房,采用 3C3D 单副本架构。
公司搬迁通知下来后,原机房需要整体停机,预计窗口 20 天。这期间站端数据采集不能停,于是我们做了一个临时决策:
核心策略
- 搬迁期间:站端数据切到公有云临时节点,继续写入;
- 搬迁结束后:把公有云积累的 TsFile 搬回原机房新部署的 IoTDB 集群。
听上去只是「临时存一下、搬回去」,但实际数据量到了近 10TB,任何一个环节没控制好,都会让回迁变成灾难。
二、20 天时间线

三、架构演进:四个阶段

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

五、关键决策与数据
决策 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

六、真实踩坑
坑 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」写进了前置检查清单。
七、验证:怎么才算「搬完了」
数据迁移不能只靠「命令跑完」,必须做四层验证:

八、复盘与建议


九、写在最后
这次迁移让我印象最深的一点是:时序数据库的搬迁,拼的不是某一个参数,而是流程的完整度。
当你面对近 10TB 数据、400 亿+ 时序点、20 天停机窗口时,任何一个环节的遗漏都会被放大。提前写好脚本、预留缓冲时间、做好验证清单,才能让一次「数据快递」安全送达。
对于 IoTDB 的使用仍在不停的学习中,欢迎大家交流分享!

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