数据库备份
受众:管理员 / 运维 / 二开开发者 摘要:后台可控的 MySQL / PostgreSQL 数据库备份能力。默认关闭,支持手动触发、定时触发、Queue 即时执行、Scheduler 定时托底、备份后校验、信封加密、密钥版本轮换、本地或远端副本、健康快照、告警通知、保留策略、文件下载、手动复验和删除。
数据库备份模块位于 spring-open-core-database-backup。它面向开发库、测试库和生产库的运维兜底:管理员可以在后台开启或关闭备份能力,设置备份目录、备份保留策略,校验备份文件,并下载已完成且可信的备份文件。
安全默认值
所有备份开关默认关闭:
| 开关 | 默认 | 说明 |
|---|---|---|
| 总开关 | 关闭 | 关闭时不允许手动或定时备份 |
| 手动备份 | 关闭 | 关闭时后台“立即备份”按钮不可用 |
| 定时备份 | 关闭 | 关闭时不会注册定时任务 |
| 压缩 | 开启 | 成功备份后默认生成 .sql.gz |
| 备份后自动校验 | 开启 | 功能开启后,每次备份落地都会重新计算 SHA-256 并读取文件内容 |
| 加密 | 关闭 | 开启后生成 .enc 文件,密钥只从服务端配置读取 |
| 副本 | 关闭 | 开启后把最终备份文件复制到副本路径,可使用本地或 Storage starter disk |
| 通知 | 关闭 | 可分别开启成功 / 失败通知 |
| 健康告警 | 关闭 | 手动健康检查发现异常时,可通过通知通道发送告警 |
这样可以避免安装后立即占用服务器硬盘。生产环境开启前,应确认磁盘容量、备份目录权限、数据库账号权限和下载权限。
支持范围
| 数据库 | 工具 | 说明 |
|---|---|---|
| MySQL | mysqldump | 从 spring.datasource.url、用户名和密码构造受控命令 |
| PostgreSQL | pg_dump | 支持 postgres / postgresql 类型 |
H2 / SQLite 等本地轻量数据库不走本模块。lite 模式如需保护数据,建议直接备份 storage/database/ 和 storage/ 目录。
后台入口
菜单入口:运维监控 / 数据库备份
后台 API 前缀:
/api/v1/admin/database-backups主要接口:
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /config | 查看备份配置 |
PUT | /config | 保存备份配置 |
GET | /health | 查看备份工具和存储路径状态 |
POST | /health/check | 手动运行健康检查并保存快照 |
GET | /keys | 查看备份加密密钥版本 |
POST | /keys/rotate | 新增 / 轮换备份加密密钥版本 |
POST | /keys/{id}/test | 测试密钥版本是否能保护和解开数据密钥 |
POST | /trigger | 手动触发一次备份 |
GET | / | 分页查询备份记录 |
GET | /{id} | 查看备份记录详情 |
POST | /{id}/verify | 手动复验备份文件 |
POST | /{id}/rekey | 使用当前活跃密钥版本重新保护历史备份的数据密钥 |
GET | /{id}/download | 下载成功备份文件 |
DELETE | /{id}/artifact | 删除备份文件并标记记录 |
POST | /cleanup | 按保留策略清理旧备份 |
存储目录
默认路径:
storage/backup/database/{databaseType}{databaseType} 会在运行时替换为 mysql 或 postgres。例如:
storage/backup/database/mysql
storage/backup/database/postgres路径必须是项目工作目录下的相对路径,不能使用绝对路径,也不能包含 ..。模块会把文件写入:
${user.dir}/<storagePath>生产建议把 storage/ 挂载到独立数据盘或持久化卷,并纳入服务器容量监控。
校验、信封加密和副本
备份文件落地后的处理顺序:
mysqldump / pg_dump
-> 可选 gzip
-> 可选 AES-GCM 信封加密
-> 写入主备份路径
-> 计算最终文件 SHA-256
-> 备份后校验
-> 可选复制副本
-> 可选发送通知- 校验:校验最终文件 SHA-256,并按文件类型读取内容;
.sql.gz会解压读取,.enc会先解密再读取。校验失败的记录会标记为失败,不作为可靠备份下载。 - 加密:开启后每个备份都会生成一个随机数据密钥(DEK),备份文件用 DEK 做 AES-GCM 加密;DEK 再由密钥版本(KEK)保护后写入记录。数据库只保存受保护的数据密钥和密钥版本元数据,不保存真实密钥材料。
spring.open.database-backup.encryption-master-keys.default.v1=<base64-or-text-key>
# 兼容旧配置,也可继续使用 keyId 或兜底密钥
spring.open.database-backup.encryption-keys.default=<base64-or-text-key>
spring.open.database-backup.encryption-key=<base64-or-text-key>这里的密钥只用于保护数据库备份文件的数据密钥,不是数据库账号密码、登录令牌、支付密钥、Web3 私钥或第三方 Provider 密钥。密钥建议使用 16 / 24 / 32 字节 AES key 的 Base64 编码;非标准长度文本会自动派生 SHA-256 key。不要把密钥写入前端、文档截图或数据库。
密钥版本表 database_backup_key_version 只保存 keyId、keyVersion、状态、Provider、算法和测试结果。轮换时可把旧版本改为 decrypt_only,新备份使用新版本;历史备份仍可解密。需要把历史记录切到新 KEK 时,使用后台“重新保护”操作,它只重包受保护的数据密钥,不重写整份备份文件。
- 副本:默认副本路径为:
storage/backup/database-replica/{databaseType}副本复制失败不会删除主备份文件,但记录会标记 replica_status=failed,并可触发失败通知。副本可以继续写本地路径,也可以写入 Storage starter 已配置的 disk,例如 minio、s3、oss、nas:
# 后台 replicaStorageDisk 填写 minio / s3 / oss / nas 等已注册 disk
spring.open.storage.disks.minio.provider=minio
spring.open.storage.disks.minio.bucket=spring-open-backup主备份文件仍先写入本地受控路径,用于校验、下载和保留策略;副本是异地 / 远端冗余,不替代主文件状态。
健康检查和告警
后台健康看板会展示:
- 备份总开关、手动 / 定时开关。
- 当前数据库类型、备份工具和工具可用性。
- 主备份路径和副本路径。
- 最近成功 / 最近失败时间。
- 连续失败次数。
- 最近校验状态和副本状态。
- 主路径 / 本地副本路径磁盘剩余空间。
- 当前活跃密钥版本和密钥测试状态。
手动点击“健康检查”会保存 database_backup_health_snapshot 快照。健康状态规则:
| 状态 | 触发条件 |
|---|---|
healthy | 已启用、工具可用、最近成功未超时、连续失败未超过阈值、磁盘空间充足 |
warning | 尚无成功备份、最近成功超出阈值、磁盘剩余低于预警阈值 |
critical | 工具不可用、连续失败达到阈值、磁盘剩余低于严重阈值或最小字节阈值 |
unknown | 备份总开关关闭 |
健康阈值可在后台配置:最近成功最大间隔、连续失败阈值、磁盘预警百分比、磁盘严重百分比和最小剩余空间字节数。开启“健康异常通知”后,手动健康检查发现 warning 或 critical 会通过配置的通知通道发送告警。
执行模型
手动和定时触发都先创建 database_backup_record 记录,再投递 Queue:
Admin / Scheduler
-> database_backup_record(pending)
-> Queue job database-backup.execute
-> mysqldump / pg_dump
-> storage/backup/database/<type>/<file>.sql.gz[.enc]
-> verify / replica / notify
-> database_backup_record(success / failed)- Queue 负责即时执行,避免管理员点击后必须等待调度轮询。
- Scheduler 只负责按 Cron 触发定时备份。
- 保留策略在每次成功备份后执行,并可通过后台手动触发。
保留策略
配置项:
| 配置 | 默认 | 说明 |
|---|---|---|
| 保留天数 | 7 | 删除完成时间早于阈值的成功备份 |
| 最大文件数 | 10 | 只保留最新成功备份 |
| 最大总大小 | 5 GiB | 超过总大小后从旧到新删除成功备份 |
删除文件会同步删除主文件和副本文件,并把记录标记为 deleted。失败记录不会自动删除,便于排查工具、权限和磁盘问题。
权限
| 权限码 | 说明 |
|---|---|
database-backup:view | 查看配置、健康检查和备份记录 |
database-backup:config | 修改备份配置 |
database-backup:trigger | 手动触发备份和清理 |
database-backup:verify | 手动复验备份文件 |
database-backup:health:check | 手动运行健康检查并保存快照 |
database-backup:key:manage | 轮换 / 测试密钥版本,重新保护历史备份数据密钥 |
database-backup:download | 下载备份文件 |
database-backup:delete | 删除备份文件 |
默认 super-admin 拥有全部权限,admin 仅拥有查看菜单和查看权限。
生产建议
- 使用权限最小的数据库只读备份账号。
- 确认服务器安装
mysqldump或pg_dump,且应用进程可执行。 - 备份目录放在持久化磁盘,不和临时目录混用。
- 根据业务数据量设置合理的保留天数、最大文件数和最大总大小。
- 不把备份文件放入公开静态目录。
- 下载权限只给可信运维角色。
- 开启加密时,把密钥放到安全配置、KMS 或 Secret 管理系统,按
keyId.keyVersion保留历史密钥版本,定期轮换并测试。 - 开启副本时优先使用独立挂载盘、NAS、MinIO、S3、OSS 等远端 disk;不要和主备份目录放在同一个易满分区。
- 开启健康告警,并根据业务 RPO 设置“最近成功最大间隔”和“连续失败阈值”。
- 定期把备份文件同步到外部安全存储,并在隔离库做恢复演练;不要在生产库自动还原备份文件。
验证命令
./mvnw -pl spring-open-core/spring-open-core-database-backup -am test -DskipITs -DskipFrontend -Dsurefire.failIfNoSpecifiedTests=false
pnpm -C views/admin typecheck
./.ai/scripts/check i18n
./.ai/scripts/check modules
git diff --check