mirror of
https://github.com/RaisFast/raisfast.git
synced 2026-09-23 16:02:25 +00:00
14 KiB
14 KiB
云备份服务设计
raisfast Cloud Backup — 私有化数据的安全网
定位:零配置、端到端加密、增量备份的云端备份服务
1. 为什么需要这个功能
| 场景 | 后果 | 用户心理 |
|---|---|---|
| 硬盘损坏 | 所有客户数据丢失 | "我用私有化就是为了安全,结果数据反而丢了?" |
| 误删数据 | 重要商机/联系人丢失 | "有没有办法恢复?" |
| 勒索病毒 | 数据被加密,无法恢复 | "我愿意花钱恢复数据" |
| 服务器故障 | 业务中断 | "备份在哪里?" |
| 迁移新机器 | 需要手动复制数据 | "能不能一键迁移?" |
私有化用户最大的焦虑 = 数据丢失没有兜底。 解决这个焦虑 = 核心卖点 + 商业化入口。
2. 设计目标
| 目标 | 说明 |
|---|---|
| 零配置 | 注册账号 → 自动备份,不需要配置 S3/Azure |
| 端到端加密 | 数据在客户端加密,云端只存密文,服务端无法解密 |
| 增量备份 | 只传输变更部分,节省带宽和时间 |
| 版本历史 | 保留 N 个历史版本,支持回滚到任意时间点 |
| 自动调度 | 每小时/每天自动备份,无需手动操作 |
| 跨平台 | 桌面应用 + 服务器都支持 |
| 一键恢复 | 选一个版本 → 一键恢复到任意设备 |
3. 技术架构
3.1 整体流程
┌─────────────────────────────────────────────────────────────┐
│ 用户设备(客户端) │
│ │
│ SQLite DB → 变更检测 → 增量计算 → AES-256加密 → 压缩 │
│ ↓ │
│ 上传到备份服务器 │
│ ↓ │
│ 备份记录(本地) ← 备份元数据 ← 备份服务器确认 │
└─────────────────────────────────────────────────────────────┘
↓ 加密数据上传
┌─────────────────────────────────────────────────────────────┐
│ 备份服务器(云端) │
│ │
│ 接收加密块 → 存储到对象存储(S3/R2)→ 记录元数据 │
│ │
│ 存储内容: │
│ ├── 用户账号信息(邮箱、设备列表) │
│ ├── 备份元数据(时间、大小、版本号) │
│ └── 加密数据块(AES-256-GCM,服务端无法解密) │
└─────────────────────────────────────────────────────────────┘
3.2 端到端加密方案
密钥层级:
用户密码
↓ Argon2id
主密钥 (Master Key)
↓ HKDF-SHA256
├── 数据加密密钥 (DEK) → 加密备份数据
├── 密钥加密密钥 (KEK) → 加密存储 DEK
└── 文件名加密密钥 (FEK) → 加密备份文件名
流程:
1. 注册时:用户密码 → Argon2id → 主密钥
2. 备份时:主密钥 → HKDF → DEK → AES-256-GCM 加密数据
3. 上传时:只传密文,服务端看不到明文
4. 恢复时:密码 → 重新派生主密钥 → 解密
安全保证:
- 服务端被黑客入侵 → 无法解密(没有用户密码)
- 备份文件泄露 → 无法解密(AES-256-GCM)
- 用户忘记密码 → 无法恢复(零知识架构)
3.3 增量备份方案
SQLite WAL 模式:
首次备份(全量):
SQLite 文件 → 分块(4MB/块)→ 每块计算 SHA-256 → 加密 → 上传
后续备份(增量):
1. 对比当前块 SHA-256 与上次备份的块列表
2. 只上传 SHA 变化的块
3. 生成新的快照清单(指向块列表)
快照 A(全量): [block-1, block-2, block-3, block-4]
快照 B(增量): [block-1, block-2, block-3-new, block-4]
↑ 只有这个变了
存储开销:每次增量只存变化的块(通常 < 1MB)
3.4 SQLite 备份具体实现
方案选择:SQLite Backup API(sqlite3_backup_init)
Step 1: 创建临时 SQLite 副本
→ 使用 SQLite Backup API 将热数据库复制到临时文件
→ 确保数据一致性(不锁库)
Step 2: 计算块哈希
→ 临时文件按 4MB 分块
→ 计算每块 SHA-256
Step 3: 增量对比
→ 与上次备份的块列表对比
→ 识别变化的块
Step 4: 加密 + 压缩
→ 变化的块 → zstd 压缩 → AES-256-GCM 加密
Step 5: 上传
→ 加密块上传到备份服务器
→ 生成新快照清单
Step 6: 清理
→ 删除临时文件
→ 保留本地备份元数据
4. 备份服务端设计
4.1 技术选型
| 组件 | 选型 | 说明 |
|---|---|---|
| 备份服务器 | Rust (Axum) | 与 raisfast 同技术栈,可独立部署 |
| 对象存储 | Cloudflare R2 | 免出站流量,S3 兼容 |
| 用户认证 | JWT | 简单可靠 |
| 数据库 | PostgreSQL | 存储用户/元数据 |
| 支付 | Stripe | 国际通用 |
4.2 API 设计
认证:
POST /api/v1/auth/register # 注册(邮箱+密码)
POST /api/v1/auth/login # 登录
POST /api/v1/auth/token # 刷新 Token
设备管理:
GET /api/v1/devices # 列出设备
POST /api/v1/devices # 注册设备
DELETE /api/v1/devices/:id # 移除设备
备份:
POST /api/v1/backups/upload # 上传备份块
POST /api/v1/backups/snapshot # 创建快照
GET /api/v1/backups/snapshots # 列出快照
GET /api/v1/backups/snapshots/:id # 获取快照详情
DELETE /api/v1/backups/snapshots/:id # 删除快照
恢复:
POST /api/v1/backups/restore/:id # 获取恢复所需的块列表
GET /api/v1/backups/blocks/:hash # 下载指定块
订阅:
GET /api/v1/subscription # 当前订阅状态
POST /api/v1/subscription/checkout # Stripe Checkout
POST /api/v1/subscription/webhook # Stripe Webhook
4.3 数据模型
-- 用户
CREATE TABLE users (
id UUID PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL, -- Argon2id
created_at TIMESTAMPTZ NOT NULL
);
-- 设备
CREATE TABLE devices (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
name TEXT NOT NULL, -- "MacBook Pro" / "Server-01"
device_key TEXT NOT NULL, -- 设备公钥指纹
created_at TIMESTAMPTZ NOT NULL
);
-- 备份快照
CREATE TABLE snapshots (
id UUID PRIMARY KEY,
device_id UUID REFERENCES devices(id),
snapshot_no BIGINT NOT NULL, -- 快照序号
size_bytes BIGINT NOT NULL, -- 原始大小
block_count INT NOT NULL, -- 块数量
created_at TIMESTAMPTZ NOT NULL
);
-- 备份块(去重)
CREATE TABLE blocks (
hash TEXT PRIMARY KEY, -- SHA-256
size_bytes INT NOT NULL,
storage_key TEXT NOT NULL, -- S3/R2 对象键
created_at TIMESTAMPTZ NOT NULL
);
-- 快照 → 块映射
CREATE TABLE snapshot_blocks (
snapshot_id UUID REFERENCES snapshots(id),
block_hash TEXT REFERENCES blocks(hash),
block_index INT NOT NULL, -- 块序号
PRIMARY KEY (snapshot_id, block_index)
);
-- 订阅
CREATE TABLE subscriptions (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
plan TEXT NOT NULL, -- free/pro/enterprise
storage_limit BIGINT NOT NULL, -- 存储上限(字节)
stripe_id TEXT, -- Stripe 订阅 ID
status TEXT NOT NULL, -- active/canceled
created_at TIMESTAMPTZ NOT NULL
);
5. 客户端集成
5.1 桌面应用集成
设置页面:
┌─────────────────────────────────────────────┐
│ 云备份设置 │
│ │
│ 账号:chris@example.com [登录/注册] │
│ 状态:✅ 已连接 上次备份:3 分钟前 │
│ │
│ 备份频率: │
│ ○ 每小时 ● 每天 ○ 每周 │
│ │
│ 备份历史: │
│ ┌─────────────────────────────────────────┐ │
│ │ 2024-04-23 14:30 12.5 MB [恢复] [删除]│ │
│ │ 2024-04-22 14:30 12.3 MB [恢复] [删除]│ │
│ │ 2024-04-21 14:30 11.8 MB [恢复] [删除]│ │
│ └─────────────────────────────────────────┘ │
│ │
│ 恢复到其他设备: │
│ [选择快照] → [生成恢复码] → 在新设备输入恢复码 │
│ │
│ [立即备份] │
└─────────────────────────────────────────────┘
5.2 CLI 集成
# 登录
rust-backup login --email chris@example.com
# 手动备份
rust-backup backup --project ./my-project
# 查看备份历史
rust-backup snapshots --project ./my-project
# 恢复到指定版本
rust-backup restore --snapshot abc-123 --output ./restored-project
# 恢复到新设备(使用恢复码)
rust-backup restore --code ABCD-1234-EFGH-5678 --output ./my-project
# 生成恢复码(在其他设备上使用)
rust-backup recovery-code --snapshot abc-123
5.3 Plugin API(可在插件中触发备份)
// 在插件中触发备份(如创建重要数据后)
Plugin.on_content_created = function(input) {
const data = parseBody(input);
if (data.content_type === "deal" && data.stage === "closed_won") {
// 赢单后自动备份
Host.backup();
}
return ok(data);
};
6. 定价
| 套餐 | 存储空间 | 保留版本 | 设备数 | 价格 |
|---|---|---|---|---|
| 免费 | 1 GB | 7 天 | 1 台 | $0 |
| Pro | 50 GB | 90 天 | 5 台 | $9.9/月 |
| Team | 500 GB | 365 天 | 无限 | $29/月 |
| Enterprise | 无限 | 无限 | 无限 | $99/月 |
6.1 成本估算
| 项目 | 单价 | 1000 个 Pro 用户成本 |
|---|---|---|
| Cloudflare R2 存储 | $0.015/GB/月 | $750(50GB × 1000 × $0.015) |
| R2 上传(Class A 操作) | $4.50/百万次 | ~$50 |
| R2 下载(恢复) | 免费(R2 无出站费) | $0 |
| 服务器(1 台) | $20/月 | $20 |
| 总成本 | ~$820/月 | |
| 收入 | $9.9 × 1000 | $9,900/月 |
| 利润率 | ~92% |
7. 开发路线
Phase 1 — 核心备份(1-2 月)
| 任务 | 说明 |
|---|---|
| 备份服务端 | Rust + Axum,用户注册/登录/上传/下载 |
| 端到端加密 | AES-256-GCM + Argon2id 密钥派生 |
| 增量备份引擎 | SQLite 分块 + SHA-256 对比 + zstd 压缩 |
| 桌面应用集成 | 设置页面 + 自动调度 + 状态显示 |
| CLI 命令 | rust-backup login/backup/restore |
Phase 2 — 恢复体验(2-3 月)
| 任务 | 说明 |
|---|---|
| 一键恢复 | 选择快照 → 一键恢复 |
| 恢复码 | 跨设备恢复(类似恢复短语) |
| 版本对比 | 对比两个快照的差异 |
| 选择性恢复 | 只恢复特定表/数据 |
Phase 3 — 高级功能(3-6 月)
| 任务 | 说明 |
|---|---|
| 团队功能 | 多设备管理、团队共享备份 |
| Point-in-time | 恢复到精确时间点 |
| 备份监控 | 备份失败告警、异常检测 |
| 合规报告 | 备份报告生成(企业审计用) |
8. 商业价值
8.1 为什么备份服务是最佳商业化入口
| 优势 | 说明 |
|---|---|
| 刚需 | 每个私有化用户都需要备份 |
| 持续付费 | 按月/年订阅,不是一次性购买 |
| 高粘性 | 备份数据在云端,用户不会轻易离开 |
| 高利润率 | 存储成本极低(~8%),利润率 90%+ |
| 信任入口 | 用户把数据交给你备份 → 建立信任 → 后续卖更多服务 |
| 天然获客 | 桌面应用内提示"开启云备份" → 零成本转化 |
8.2 与主产品的协同
raisfast 开源版(免费)
↓ 用户使用,积累数据
↓ 看到备份提示
rust-backup 云备份(付费)
↓ 用户付费备份
↓ 建立信任
↓ 推荐其他付费服务
raisfast 企业插件包(付费)
raisfast 行业模板包(付费)
raisfast 技术支持(付费)
备份是整个商业化飞轮的起点。