备份与恢复
元数据库、数据目录与连接密钥必须成对备份:备份内容与工具、各部署形态的备份方法、校验演练、恢复步骤与常见故障。
概述
适用版本:v2.0.5 及之后(tools/backup.sh / tools/restore.sh 随发布包提供)。适用部署:单机 Docker Compose、原生包(systemd)、多实例集群;元数据库为 PostgreSQL 族 / MySQL 族 / 内置 H2。
铁律:元数据库、
FDL_DATA_DIR数据目录、连接密钥(FDL_CONNECTION_SECRET_KEY,或安装向导生成的datalink.properties/connection-secret.key)必须一起备份、一起恢复。只恢复库而丢了密钥,所有已保存的数据源密码都解不开;只恢复旧密钥而库是新的,配置会回退。元数据库迁移不可逆,回滚必须连库一起恢复。
目标与保留策略
| 项目 | 建议值 | 说明 |
|---|---|---|
| RPO(可接受丢多少数据) | 生产不超过 15 分钟;一般不超过 2 小时 | 元数据库存的是配置、发布版本、运行记录、审计;数据源里的业务数据不在本备份范围 |
| RTO(恢复要多久) | 30 到 60 分钟(元数据库不超过 10 GB) | 时间主要花在拉备份、数据库恢复、解包数据目录、重启与冒烟 |
| 保留策略 | 每日 30 份 + 每周 12 份 + 每月 12 份 | 至少 1 份离线或异机,备份目录本身要加密 |
| 演练频率 | 每季度一次,以及每次大版本升级前 | 用 --verify 与一次真实恢复到临时库验证 |
备份内容
tools/backup.sh 产出:
| 文件 | 内容 |
|---|---|
metadata-db/postgresql.dump |
PG 族 pg_dump -Fc(含 openGauss / 金仓,可用 PG_DUMP 指向厂商兼容工具) |
metadata-db/mysql.sql |
MySQL / MariaDB mysqldump(--single-transaction,含 routines、triggers、events) |
metadata-db/<库名>.mv.db |
内置 H2 的库文件副本(必须先停服务) |
data.tar.gz |
整个 FDL_DATA_DIR:连接密钥、自备 JDBC 驱动、受管文件、H2 数据目录、文件传输目录 |
manifest.json / manifest.sha256 |
每个文件的 sha256 与大小、UTC 时间、产品版本、库类型、脱敏后的连接地址 |
RESTORE.txt |
本次备份的恢复命令与密钥提醒 |
口令只经环境变量 PGPASSWORD 或权限 0600 的临时配置文件传给客户端,不出现在命令行、不打印;备份目录权限为 700。
日常备份
Docker Compose
宿主机通常看不到容器内的数据目录。推荐从宿主机直连元数据库,数据目录用 docker cp 取出:
export DB_URL='jdbc:postgresql://127.0.0.1:5432/dfdatalink' DB_USERNAME=fdl DB_PASSWORD='***'
mkdir -p /backup/datalink-data
docker compose cp app:/var/lib/sight-datalink/. /backup/datalink-data/ # 含密钥,请加密归档
tools/backup.sh --dir /backup/datalink --data-dir /backup/datalink-data
也可以在 app 容器内运行脚本,但容器内默认没有 pg_dump / mysqldump,需要自行安装客户端,生产环境更推荐上面的方式。
原生包(systemd,元数据库外部)
sudo install -d -m 700 /backup/datalink
DB_PASSWORD="$(sudo sed -n 's/^DB_PASSWORD=//p' /opt/sight-datalink/sight-datalink.env)" \
sudo -E tools/backup.sh --dir /backup/datalink --data-dir /opt/sight-datalink/data
内置 H2(必须停服务)
sudo systemctl stop sight-datalink
tools/backup.sh --dir /backup/datalink --data-dir /opt/sight-datalink/data \
--db-url 'jdbc:h2:file:/opt/sight-datalink/data/db/dfdatalink'
sudo systemctl start sight-datalink
脚本会通过 lsof / fuser 与 .lock.db 检测占用,服务运行时拒绝复制。容器内探测不到时,必须先停容器,再加 --assume-stopped,并在事后校验。停机窗口就是 H2 的备份窗口,这也是生产不建议用 H2 的原因之一。
非 Linux 环境
tools/backup.sh / tools/restore.sh 是 bash 脚本,在 Linux 之外同样可用,但要注意:
- Docker Desktop(macOS / Windows):数据目录在虚拟机里,用
docker compose cp取出后再备份;内置 H2 必须先docker compose stop app,再按提示使用--assume-stopped。 - macOS 本地:显式用
bash tools/backup.sh …调用;没有sha256sum时脚本自动回退到shasum -a 256。 - Windows:优先在 WSL2 中运行,把备份放在 WSL 文件系统而不是
/mnt/c。 - Time Machine、文件历史、云盘同步不能替代数据库一致性备份,只能作为额外副本。
定时备份
# 每天 02:30(示例,先手动跑通再启用)
30 2 * * * cd /opt/sight-datalink && DB_URL=... DB_USERNAME=... DB_PASSWORD=... \
tools/backup.sh --dir /backup/datalink >> /var/log/fdl-backup.log 2>&1
备份失败要接入通知(cron 默认只发本地邮件);建议再加一条外部告警:备份目录最后修改时间超过 26 小时。
校验与演练
# 校验清单、sha256、归档完整性与目标库连通性(只读,不写任何数据)
tools/restore.sh --dir /backup/datalink/sight-datalink-backup-20261030T020000Z \
--db-url 'jdbc:postgresql://db:5432/datalink' --db-user fdl \
--data-dir /tmp/fdl-restore-drill --verify
--verify 会校验 manifest.sha256、逐个文件的 sha256 与大小、data.tar.gz 是否可解包,以及目标库族一致性与连通性。
季度演练:把备份恢复到临时库与临时目录,启动一个临时实例(换端口),登录、打开一个数据源「测试连接」、抽查运行记录,记录实际 RTO,完成后删除临时实例。
恢复步骤
# 0. 先停服务(H2 必须;外部库也建议停,避免恢复期间写入)
sudo systemctl stop sight-datalink # 或 docker compose stop app
# 1. 恢复(会覆写目标元数据库;旧数据目录改名为 <data-dir>.pre-restore-<UTC> 保留)
tools/restore.sh --dir '/backup/datalink/sight-datalink-backup-20261030T020000Z' \
--db-url 'jdbc:postgresql://db:5432/datalink' --db-user fdl --db-password '***' \
--data-dir /opt/sight-datalink/data --yes
# 2. 确认连接密钥:环境变量部署要设回与备份时相同的 FDL_CONNECTION_SECRET_KEY;
# 向导部署确认 data/datalink.properties / connection-secret.key 已随数据目录恢复。
# 3. 启动并冒烟
sudo systemctl start sight-datalink
- 跨版本恢复:恢复后的库对应备份时的产品版本。若当前程序更新,先换回同版本,再按正常流程升级;不支持把元数据库原地降级。
- 恢复到新机器:先安装同版本,准备空数据目录与空库,再执行
restore.sh;不要先让新实例跑迁移建表,PostgreSQL 恢复使用--clean --if-exists,会先删除目标库里的对象。
保管与访问控制
- 备份目录包含连接密钥与全部配置,按生产数据对待:归档后再加密(age / gpg / 云 KMS),加密口令与备份分开存放。
- 至少 2 份,其中 1 份离线或对象存储(不可变 / 版本化);上传后核对
manifest.sha256。 - 备份账号只需要只读库权限加数据目录读权限;不要把生产
DB_PASSWORD写进 crontab。 - 团队至少两人掌握恢复流程;恢复权限与生产库写权限同等敏感。
恢复后冒烟清单
GET /api/health与GET /api/health/ready均返回 200。- 管理员登录成功;用户、角色、最近编辑的任务与管道在列表里。
- 打开一个数据源点「测试连接」:能解密密码且能连目标库(证明密钥与库匹配)。
- 运行记录里能看到历史记录;手动跑一个小任务成功。
- 平台日志里能看到本次登录的审计记录;
GET /api/system/actuator/prometheus可抓取。 - 旧数据目录
<data-dir>.pre-restore-<UTC>保留,观察 1 到 2 天后再清理。 - 记录恢复开始与结束时间、实际 RTO;超过目标则更新目标并补演练。
常见故障
| 现象 | 处理 |
|---|---|
pg_restore 报 version mismatch |
使用不低于备份服务器主版本的 pg_restore |
pg_restore 中途失败 |
目标库可能半恢复:清空目标库重建后再跑一次 restore.sh,不要直接启动服务 |
| 起服务后数据源「凭据不可读取」 | 密钥与库不匹配:设回备份时的 FDL_CONNECTION_SECRET_KEY,或恢复随包的 connection-secret.key / datalink.properties |
| H2 提示文件被占用 | 服务没停干净:停止后确认 lsof <库>.mv.db 为空再重试 |
MySQL 恢复报 utf8mb4 字符集错误 |
目标库需使用 CHARACTER SET utf8mb4 COLLATE utf8mb4_bin |
| 备份目录被删但服务仍正常 | 仍在运行的连接密钥无法恢复,只能重新录入数据源密码;先补一份新备份并检查保留策略 |
与升级的衔接
- 升级前必须完成一次校验通过的备份,并在升级记录里写明备份路径与
manifest.sha256,见 升级与回滚。升级前体检脚本tools/preupgrade-check.sh --backup-dir <备份目录>会把最近备份的年龄与 manifest 校验纳入检查。 - 回滚 = 恢复库 + 数据目录 + 密钥,三者缺一不可;不允许原地降级,也不允许只换回旧 jar 而不恢复库。
- 多实例集群没有自动跨实例一致性快照,备份期间其他实例仍可能写入。生产建议在固定维护窗口内先停全部实例再备份,或接受 RPO 内的少量丢失并在恢复后核对运行记录。
演练记录模板
日期: 演练人:
备份目录 / sha256:
备份时版本: 恢复目标版本:
开始时间: 恢复完成时间: 实际 RTO:
校验(--verify):通过 / 失败(原因)
冒烟 1–6 项: 1☐ 2☐ 3☐ 4☐ 5☐ 6☐
发现的问题: 下次改进: