备份与灾备说明
初稿(2026-11-05)。适用于私有化部署(单机 Docker Compose 与 Kubernetes)。部署形态见《产品架构与部署白皮书》;加密与访问控制见《安全白皮书》。
1. 数据在哪里
| 数据 | 内容 | 存放位置 |
|---|---|---|
| PostgreSQL 集群 | 平台业务库(租户、业务数据、草稿等)、审计库、身份(Zitadel)的库、工作流(Temporal)与各工具的库 | Postgres 数据卷 |
| OpenBao | 敏感字段的数据密钥、租户凭据(自带存储、自带模型的密钥)、派生密钥的根 | OpenBao 数据卷(文件存储) |
| 平台文件 | 上传的文件、头像、录音、审计归档分段 | single:kwork 数据卷;onprem:自带 SeaweedFS;云 Pack:云厂商的桶 |
| 配置与密钥 | 安装时生成的全部密钥(含备份加密密钥)、导出的网关根证书 | 主机上的部署配置目录 |
| 许可证 | 许可证文件与厂商公钥 | 主机上的部署配置目录 |
| 租户自带存储 | 租户自己配置的 S3 / OSS / COS / MinIO 桶里的文件 | 租户自己的桶 |
2. 备份方式与频率
| 数据 | 方式 | 频率 | 怎么打开 |
|---|---|---|---|
| PostgreSQL 整个集群 | WAL-G:经复制协议持续接收 WAL,加密后上传到 S3 兼容存储;每天一次全量 | WAL 持续(每 60 秒强制切换一次 WAL 段);全量每天 02:30 UTC,默认保留最近 7 个 | 安装时加 backup;默认不打开 |
| OpenBao 数据卷、kwork 数据卷、配置与密钥 | 状态包:一次打成一个加密归档,可直接上传到 S3 兼容存储 | 每次执行一个;按每日执行配置定时任务(由你配置) | 随平台提供,需你安排定时执行 |
| 许可证 | 不在任何备份里 | 换文件时 | 厂商给的原件另存 |
- 数据库备份不改动、不重启 Postgres 服务,只通过网络读取。
- 备份服务有健康检查:WAL 流在运行、上一次全量不超过 26 小时。不满足时显示为不健康。
- 升级脚本在打开备份时,升级前先做一次全量备份和一次状态包。
- 不打开数据库备份的安装,至少每天自行做一次数据库导出。
- 以上备份服务与状态包只用于单机 Compose 形态。Kubernetes 形态的 PostgreSQL、对象存储与 OpenBao 由你提供,按所用服务的方式备份(例如托管数据库自带的时间点恢复)。
2.1 备份送到哪里
onprem不另行配置时,数据库备份送到自带的 SeaweedFS。它还在同一台主机上:主机或磁盘整体损坏时备份也会丢失。生产环境请指向另一个机房或云上的存储。巡检(kwork doctor的backup_offsite)在备份送到同一台主机时给出提醒。single与云 Pack 必须先配置备份存储,否则安装拒绝打开备份。- 建议:备份存储的凭据只授权这一个桶;桶开启版本控制,可能时开启对象锁定,防止主机被入侵后备份被删除。
3. 加密与密钥保管
| 对象 | 加密 | 密钥 | 谁保管 |
|---|---|---|---|
| 数据库全量与 WAL | 在主机上用 libsodium(secretbox)加密后才上传,存储方看不到内容 | 备份加密密钥(32 字节,安装打开备份时生成) | 你:生成后立即离线另存,至少两份 |
| 状态包 | AES-256-CBC,PBKDF2 派生(200,000 轮) | 同一把备份加密密钥 | 同上 |
| OpenBao 数据 | OpenBao 自身封存 | 5 份解封密钥,任意 3 份可解封 | 你指定的不同保管人,各自离线保存 |
- 丢了备份加密密钥,所有数据库备份和状态包都无法打开,没有任何恢复办法。不要只放在这台主机上。
- 更换备份加密密钥只对之后的备份生效;旧备份仍需旧密钥,旧全量过了保留期之后才能丢弃旧密钥。
- 解封密钥在初始化时写入主机上的一个文件。分发给保管人后要从主机删除该文件:否则它会进入状态包,解封份额、OpenBao 数据和加密密钥会出现在同一个包里,3/5 分持失去意义。OpenBao 的 root token 同样离线保存。巡检(
kwork doctor的unseal_file)只看这个文件在不在、放了多久,不读内容:在就提醒,超过 7 天报异常。 - OpenBao 每次重启后都处于封存状态,需要 5 位保管人中任意 3 位输入各自的份额解封;封存期间平台的就绪检查失败。目前没有自动解封。
- 数据库备份角色可以读到整个集群的数据文件,其密码按超级用户密码的级别保管。
4. RPO 与 RTO
RPO 是可能丢失的数据时间窗口;RTO 是恢复所需时间。
| 项 | 值 | 类型 |
|---|---|---|
| RPO | ≤ 5 分钟 | 目标 |
| RTO | ≤ 1 小时(SaaS 的目标;私有化部署的 RTO 取决于你的备份存储、数据量与演练结果) | 目标 |
| 丢数据窗口(设计上限) | 约 60 秒加上传时间(由 WAL 段切换间隔决定) | 配置值 |
| 丢数据窗口:源库被强制杀掉并删除数据卷后恢复 | 33 秒 | 实测 |
| 丢数据窗口:恢复后的第二条时间线 | 55 秒 | 实测 |
| 丢数据窗口:对运行中的完整平台数据库做备份并恢复 | 42 秒 | 实测 |
| 数据库恢复耗时:329 MB 集群,最新全量 + 全部 WAL,冷启动 | 35.4 秒 | 实测 |
| 数据库恢复耗时:时间点恢复 | 17.4 秒 | 实测 |
| 数据库恢复耗时:514 MB 的完整平台数据库 | 13.0 秒 | 实测 |
实测条件(2026-10-06):开发机上的 Docker 虚拟机(aarch64,4 核,与其他任务共用,磁盘 I/O 慢),存储为同网络的 SeaweedFS。恢复耗时只是数据库部分,不含新主机准备、状态包解开、OpenBao 解封和服务启动。按这次的速度粗算,取全量约 17 MB/s。
尚未实测的:
- 几十 GB 到 TB 级数据的全量与回放耗时;
- 跨机房、跨地域的备份存储,以及云厂商的对象存储(AWS S3、阿里云 OSS、腾讯云 COS);
- 把恢复出的数据库换回正在运行的平台,以及整机重建的端到端耗时;
- 7 天保留期的自然轮转;复制槽超过 8 GB 被放弃后的追赶。
5. 恢复演练
数据库恢复演练不碰正在运行的平台:
- 演练脚本在一个一次性的容器和数据卷里取出全量、从备份存储取 WAL 回放到末尾(或指定时间点),然后提升为主库。
- 恢复出的数据库只开本地 socket,不监听网络、不归档,网络上的任何服务都连不到它。
- 脚本检查业务库、审计库、身份库都在,报告租户数、迁移版本、审计事件数与最新事件时间,并与运行中的源库对比落后多少数据。
- 打印每一段的耗时:这就是你环境里数据库部分的 RTO。
- 结束后容器和数据卷全部删除。
状态包演练:用离线保存的那份备份加密密钥(不读主机上的配置)把最新状态包解到一个临时目录,确认 OpenBao 数据在其中。这同时证明离线保存的密钥是对的。
建议频率:上线前一次,之后每季度一次(单机 Beta 环境建议每月一次)。整机重建演练的顺序:新主机装好 Docker → 放上同一版本的部署文件与许可证 → 用离线密钥解开状态包并放回配置、密钥与 OpenBao 数据 → 恢复数据库到指定时间点 → 启动平台 → 保管人解封 OpenBao → 登录、打开一个已有文件、对每个租户校验审计链。网关的内置 CA 不在备份中,重建后会生成新的根证书,要重新分发给用户和运维人员。
6. 时间点恢复
- 可以把数据库恢复到保留期内的任意时间点:默认保留最近 7 个每日全量及其之后的 WAL。
- 实测:目标时间设在两批写入之间,恢复结果准确落在两批之间(第一批在、第二批不在)。
- 真实恢复时先停止所有写入数据库的服务,把旧数据移到另一个数据卷(不删除),再恢复到空目录。恢复只往空目录写。
- 恢复之后数据库进入新的时间线,要立刻做一次全量备份。
- 时间点恢复会丢掉该时间之后的全部改动,要告知用户。
- 数据库与 OpenBao 要恢复到同一时期,否则依赖派生密钥的退订链接与站点会话会失效。
7. 不在平台备份范围内的
| 数据 | 说明 |
|---|---|
| 租户自带存储里的文件 | 在租户自己的桶里,由租户开启版本控制或跨地域复制 |
| 云 Pack 的平台文件桶 | 在你的云账号里,由你开启版本控制或跨区复制 |
onprem 自带 SeaweedFS 里的平台文件与审计归档 | 不在状态包里,需另做复制 |
| 网关证书与内置 CA | 不备份;重建后重新签发 |
| 观测数据(指标、日志、链路、Langfuse)、模型网关的本地数据 | 不备份;模型网关的供应商与密钥由平台重新同步 |
| 许可证文件与厂商公钥 | 厂商给的原件另存 |
| 主机磁盘快照 | 不由平台提供;云主机可使用云厂商的快照 |
8. 当前限制
- 单机部署不是高可用:主机故障期间平台不可用,按本文 §5 的顺序在新主机上重建。
- 多可用区与异地灾备没有提供。备份可以送到另一个地域的存储,但没有自动切换。
- 数据库主备切换:只适用于 Kubernetes 形态,由你提供的 Postgres 负责切换,平台连跟随主库的地址。已在单节点测试集群上用 CloudNativePG(一主一备、异步复制)实测计划切换、删除主库、进程被杀、网络隔离、进程冻结五种场景,写入在约 2.5 秒到 126 秒内恢复,取决于场景。异步复制下非计划切换会丢失尚未复制到备库的已提交写入,实测中出现过“变更已生效、审计没写上”。同步复制、托管数据库(RDS、PolarDB 等)的切换、PgBouncer、多节点集群的真实节点故障都没有测。
- OpenBao 需要人工解封:每次主机或 OpenBao 重启后,由保管人解封。
- 审计归档的对象锁定:自带的 SeaweedFS 不支持对象锁定,此时归档是未锁定的独立副本;要锁定,换用支持对象锁定的 S3 兼容存储。