尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

ThingsBoard:多租户备份的 3 步落地与踩坑记录

ThingsBoard:多租户备份的 3 步落地与踩坑记录 ThingsBoard多租户备份的 3 步落地与踩坑记录【免费下载链接】thingsboardOpen-source IoT Platform - Device management, data collection, processing and visualization.项目地址: https://gitcode.com/GitHub_Trending/th/thingsboard凌晨三点监控面板突然一片红某租户的设备批量离线规则链没有触发任何告警。你查库想回滚才发现那个租户的仪表板上周被误删而最后一次手动备份停在两个月前——那时候你还在想系统就一台数据库好像也不用太早做备份。ThingsBoard 多租户架构下一个租户的误操作可能污染整个共享库多租户备份不是可选项是底线。下面这套流程按顺序做完大概 30 分钟。方案全貌四段式流水线整条链路是列出租户 → 按租户导出 SQL → 压缩归档 → 行数校验。数据源Docker 里的 Postgres 16 容器thingsboard_postgres_1执行者docker/目录下两个 shell 脚本 宿主机 crontab产出./backups/tenant_id_日期/下每租户一组.sql.gz文件外加一份校验日志兜底校验失败的租户会写入独立 error log接你的告警渠道前置准备环境、权限与文件位置Docker Compose 部署的 ThingsBoardPostgres 容器名为thingsboard_postgres_1数据库名thingsboard参考 docker/docker-compose.postgres.yml宿主机装好docker、curl、jq、gzip当前用户能crontab -e一个 ThingsBoard 管理员账号能调 REST API 拿到 JWT了解表结构实体表统一带tenant_id列建表语句在 dao/src/main/resources/sql/schema-entities.sql关键结论ts_kv_*时序分区表是全局共享的按时间分区不是按租户租户级隔离只对实体表直接生效时序数据要单独处理——这决定了下面脚本的写法逐步实施第一步编写单租户导出脚本为什么先做单租户脚本批量逻辑只是循环调用它单独跑通一个租户比整体调试便宜得多。创建docker/backup_tenant.sh#!/bin/bash # docker/backup_tenant.sh —— 单租户备份 TENANT_ID$1 OUT./backups/tenant_${TENANT_ID}_$(date %Y%m%d) mkdir -p $OUT # 实体表有 tenant_id 列直接用 --where 过滤 docker exec thingsboard_postgres_1 pg_dump -U postgres -d thingsboard \ -t device -t customer -t dashboard -t rule_chain \ --wheretenant_id$TENANT_ID $OUT/business.sql # 时序是全局共享分区表无法按租户过滤整表导出 docker exec thingsboard_postgres_1 pg_dump -U postgres -d thingsboard \ -t ts_kv_* $OUT/ts_kv.sql gzip $OUT/*.sql验证点ls -lh ./backups/出现business.sql.gz和ts_kv*.sql.gz且zcat business.sql.gz | head -20能看到CREATE TABLE和INSERT语句。⚠️ 如果business.sql.gz只有几百字节多半是TENANT_ID传错先停下来查 ID。第二步列出租户 ID 并用 crontab 调度多租户备份为什么用 API 而不是查库REST 接口是官方支持的入口租户增删后脚本自动跟随不用改代码。创建docker/backup_all_tenants.sh# docker/backup_all_tenants.sh TENANT_IDS$(curl -s http://localhost:8080/api/tenant/tenants/100/0 \ -H X-Authorization: Bearer $JWT_TOKEN | jq -r .data[].id.id) [ -z $TENANT_IDS ] exit 1 # API 挂了要立刻失败不能静默 for id in $TENANT_IDS; do ./docker/backup_tenant.sh $id done挂定时任务每日 02:00 执行crontab -e # 追加一行全部用绝对路径 0 2 * * * /opt/thingsboard/docker/backup_all_tenants.sh /var/log/tb_backup.log 21验证点先手动跑一次./docker/backup_all_tenants.sh./backups/下每个租户一个独立目录数量与 UI 里租户数一致。租户实体的定义可以对照 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java。第三步给多租户备份加上行数校验为什么加校验压缩成功的空文件同样会骗过你的ls只有比过行数才算数。创建docker/verify_backup.sh在批量脚本的每次单租户备份后调用#!/bin/bash # 线上库该租户 device 行数 PRE$(docker exec thingsboard_postgres_1 psql -U postgres -d thingsboard \ -tAc SELECT count(*) FROM device WHERE tenant_id$1) # 备份文件里同表的 INSERT 行数 POST$(zcat ./backups/tenant_${1}_*/*.sql.gz | grep -c ^INSERT INTO device) if [ $PRE -eq $POST ]; then echo 备份验证成功: $1 else echo 备份验证失败: $1 /var/log/tb_backup_error.log fi验证点/var/log/tb_backup_error.log不存在或为空tb_backup.log里每个租户一行备份验证成功。验证与异常处理手动恢复一次才算闭环把某个租户的business.sql.gz解压后灌进一个空的测试库再SELECT count(*)对比。常见报错现象原因解法pg_dump: relation ts_kv_XXX does not exist手写死表名时序表按时间滚动建分区一律用通配-t ts_kv_*TENANT_IDS为空导致什么都没跑JWT 过期或 API 路径写错先单独curl验证脚本里保留[ -z ... ] exit 1校验 FAIL 但差几行pg_dump非严格一致点快照可接受则记录差异值不可接受改用pg_basebackup做库级兜底凌晨目录只涨不清磁盘告警没有保留策略加一行find ./backups -name *.gz -mtime 30 -delete只留 30 天crontab 没执行shell 环境缺 PATH全部写绝对路径并把JAVA_HOME等写进脚本头部进阶与优化并行化租户多时把 for 循环换成echo $TENANT_IDS | xargs -P 4 -I{} ./docker/backup_tenant.sh {}注意 Postgres 连接数上限异地化备份完成后同步到 S3 或 NFS 挂载点本机备份只能防误操作防不了机房级故障收窄范围时序数据量大时ts_kv_*整表导出换成只导近 N 天分区分区表名本身含年月如ts_kv_2026_08更早的历史走库级全备收尾给你的数据补上一层保险单租户脚本、批量调度、行数校验三件套跑通后某个租户数据找不回来就从事故降级成运维动作。想深入看数据层实现直接读 dao/src/main/java/org/thingsboard/server/dao/tenant/ 下的缓存与 DAO 实现部署形态差异则对照 docker/docker-compose.postgres.yml 里的服务依赖顺序。【免费下载链接】thingsboardOpen-source IoT Platform - Device management, data collection, processing and visualization.项目地址: https://gitcode.com/GitHub_Trending/th/thingsboard创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表