三步跑通ThingsBoard多租户备份:定时任务+恢复演练+行数核对完整方案
2026/9/6 17:09:15 网站建设 项目流程

三步跑通ThingsBoard多租户备份:定时任务+恢复演练+行数核对完整方案

【免费下载链接】thingsboardOpen-source IoT Platform - Device management, data collection, processing and visualization.项目地址: https://gitcode.com/GitHub_Trending/th/thingsboard

凌晨三点,一位租户反馈设备历史曲线"断档",排查发现当天全库备份因磁盘满静默失败——手动 pg_dump 一次要十几分钟,还总漏核对。用这套方案做完:ThingsBoard 每天凌晨自动完成整库备份,逐租户核对实体行数,并真实导入临时库做恢复演练,备份是否"能用"当天就有结论。

环境与前置条件

项目要求
运行方式docker compose 部署,Postgres 服务来自 docker/docker-compose.postgres.yml
数据库库名thingsboard,账号/密码以 compose 文件中的POSTGRES_DBPOSTGRES_PASSWORD为准
宿主机已安装bashcron;备份目录建在仓库外,如/opt/tb-backup
主配置application/src/main/resources/thingsboard.yml,注意 EDQS 本地模式下 RocksDB 数据目录(edqs.local.rocksdb_path),它不在 pg_dump 覆盖范围内
租户模块租户 CRUD 见 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java
卷持久化数据卷参考 docker/docker-compose.volumes.yml

数据层:先搞清楚租户数据存在哪

ThingsBoard 的租户隔离是"行级"的:deviceassetcustomer等业务表都带tenant_id列(见 dao/src/main/resources/sql/schema-entities.sql),时序数据统一落在ts_kv/ts_kv_latest里、按entity_id定位,而不是每个租户一张表。所以备份粒度是"整库 dump",租户维度的核对放在校验阶段做:

-- 实体表结构(schema-entities.sql 节选) CREATE TABLE IF NOT EXISTS device ( id uuid ..., tenant_id uuid NOT NULL, -- 租户隔离列 ... ); -- ts_kv_latest 按 (entity_id, key) 为主键,实体归属于租户

提示:如果 EDQS 以 local 模式启用(edqs.mode: local),还要把rocksdb_path指向的目录一并打包,否则设备时序查询层的数据不在备份里。

数据层结论:一次pg_dump覆盖全部租户,下面交给定时任务。

调度层:凌晨两点自动全量备份

备份脚本放在仓库外的/opt/tb-backup/,核心是"dump + 逐租户计数留底":

#!/usr/bin/env bash # /opt/tb-backup/tb_backup.sh set -euo pipefail DB="thingsboard" STAMP=$(date +%Y%m%d-%H%M%S) OUT="/opt/tb-backup/dumps" mkdir -p "$OUT" PG_CTR=$(docker ps --format '{{.Names}}' | grep -i postgres | head -1) docker exec -e PGPASSWORD=postgres "$PG_CTR" \ pg_dump -U postgres -Fc "$DB" > "$OUT/tb_$STAMP.dump" # 留底:每个租户的设备数,恢复后逐行比对 docker exec -e PGPASSWORD=postgres "$PG_CTR" psql -U postgres -d "$DB" -tA \ -c "SELECT 'tenant '||id||' devices='||count(*) FROM device GROUP BY 1" \ > "$OUT/counts_$STAMP.txt" md5sum "$OUT/tb_$STAMP.dump" > "$OUT/tb_$STAMP.md5"

用 crontab 接管调度即可:

# crontab -e 0 2 * * * /opt/tb-backup/tb_backup.sh >> /var/log/tb-backup.log 2>&1

调度层跑通后,还要回答一个问题:dump 文件完好不等于数据可用,进入校验层。

校验层:恢复不出来等于没备

选"恢复演练 + 行数比对"两招。演练脚本把最新 dump 灌进一个临时库,核对后直接删库,全程不影响生产:

#!/usr/bin/env bash # /opt/tb-backup/verify_restore.sh 用法: verify_restore.sh <dump文件> DUMP=$1 TMP_DB="tb_restore_test" PG_CTR=$(docker ps --format '{{.Names}}' | grep -i postgres | head -1) docker exec -e PGPASSWORD=postgres "$PG_CTR" createdb -U postgres "$TMP_DB" docker exec -i -e PGPASSWORD=postgres "$PG_CTR" \ pg_restore -U postgres -d "$TMP_DB" < "$DUMP" # 与备份时留底的 counts_*.txt 逐租户比对 docker exec -e PGPASSWORD=postgres "$PG_CTR" psql -U postgres -d "$TMP_DB" -tA \ -c "SELECT 'tenant '||id||' devices='||count(*) FROM device GROUP BY 1" \ | diff <(cat /opt/tb-backup/dumps/counts_*.txt | tail -1) - \ && echo "VERIFY_OK $DUMP" || echo "VERIFY_FAIL $DUMP" docker exec -e PGPASSWORD=postgres "$PG_CTR" dropdb -U postgres "$TMP_DB"

提示:把verify_restore.sh也加进 crontab(如每日 3 点校验前一天的 dump),并在grep VERIFY_FAIL /var/log/tb-backup.log上接监控告警;监控侧配置可参考 monitoring/src/main/conf/tb-monitoring.conf 的写法。

FAQ:最常踩的三个坑

Q:脚本里找不到 postgres 容器,pg_dump没输出?A:PG_CTR取的是docker ps里名字含 postgres 的容器。换过部署方式(如独立部署的 RDS)时,改成直连:pg_dump -h <host> -U postgres -Fc thingsboard

Q:mkdir: cannot create directory '/opt/tb-backup':Permission deniedA:cron 以哪个用户跑就以哪个用户建目录。确认crontab -l所属用户,用sudo -u 该用户 mkdir -p建好并授权,再执行脚本。

Q:恢复演练时pg_restore报错退出?A:-Fc自定义格式必须用pg_restore还原,不能用psql -f;报错多为目标库版本高于源库。演练库createdb的报错(已存在)可先dropdb再重试。

进阶方向

数据量涨到几十 GB 后,换成pg_basebackup+ WAL 归档做增量链路,dump 文件再经rclone/aws s3同步到异地,保留策略建议"日备 30 天 + 月备 12 个月"。整篇方案只有两个脚本加两条 cron:备份自动跑、结果自动验,出问题时你拿到的是"哪一行数据丢了",而不是一个无法判断好坏的压缩包。

【免费下载链接】thingsboardOpen-source IoT Platform - Device management, data collection, processing and visualization.项目地址: https://gitcode.com/GitHub_Trending/th/thingsboard

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询