Files
raisfast/docs/cloud-backup-design.md
T

14 KiB
Raw Blame History

云备份服务设计

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 APIsqlite3_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/月 $75050GB × 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 技术支持(付费)

备份是整个商业化飞轮的起点。