Files
wordcloud/docs/DATA_STORAGE_OPTIMIZATION.md
T

6.0 KiB
Raw Blame History

业务数据存储优化与指标报告

状态:已完成第一阶段可审计代码改造;未执行破坏性清理。 目标:减少无效任务文件、把任务元数据从“内存 + 散落目录 JSON”提升为“可恢复元数据存储”,并为后续 PostgreSQL 迁移留出接口。

1. 优化前现状

任务存储

  • 任务状态 / 事件只存在于 JobManager._jobs 内存中,服务重启即丢失。
  • POST /api/jobs 每次提交都会立刻创建 service_workspace/{job_id}/inputoutput 和配置文件。
  • 任务完成后没有 TTL / 引用检查清理逻辑;历史任务目录会一直留在磁盘。
  • service_workspace 中大量任务目录只是“曾经跑过一次”的产物,没有被任何素材或模板引用。

素材存储

  • 素材文件保留在 service_assets/{asset_id}/asset.*,元数据写在目录内 meta.json
  • 普通的 POST /api/assets 没有写入 sha256,只有 .wcd 导入路径开始做内容去重。
  • 前端贴纸 tint 仍放在 localStorage,没有回到服务端统一维护。

当前实际磁盘基线(2026-08-06 扫描)

数量 / 大小
service_workspace 任务目录 193 个
service_workspace 总大小 2.44 GiB / 2,618,726,669 bytes
被素材 job_id 引用的任务目录 6 个
未被任何素材引用的任务目录 187 个
未引用任务目录总大小 2.38 GiB / 2,556,506,642 bytes
素材文件 40 个,合计约 95.6 MiB
素材中重复内容多占空间 6 个额外文件,约 2.34 MiB
设计模板 JSON 4 个

2. 优化方案与已落地改动

1) 新增业务元数据存储层

新增 backend/service/metadata_store.py

  • SQLite 单文件 backend/service_metadata/app.db
  • jobsjob_events 两张表。
  • 任务创建、状态更新、产物路径、SSE 事件都会落库。
  • JobManager 启动时可以从数据库恢复任务,不再完全依赖内存。
  • 表结构有意保持“一行元数据 + JSONB/JSON 字段”风格,后续迁移到 PostgreSQL 时主体字段不变。

2) 任务目录可审计与可清理

扩展 backend/service/storage.py

  • job_dir_size() / job_dir_info():按任务统计占用。
  • stale_job_dirs():按“未被素材引用、不在元数据库、可选按年龄”筛选遗留目录。
  • remove_job_dir():提供精确清理,只清理 service_workspace 下的任务目录。

新增 backend/service/storage_metrics.py

  • 默认 dry-run,只扫描并输出可回收空间。
  • 只有显式 --apply 才会删除遗留任务目录。
  • 示例:
cd backend
.venv/bin/python -m service.storage_metrics --max-age-days 0
.venv/bin/python -m service.storage_metrics --max-age-days 0 --json ../docs/storage-metrics.json
# 确认后执行
.venv/bin/python -m service.storage_metrics --max-age-days 0 --apply

3) 素材去重基础

  • .wcd 导入路径已按 sha256 去重素材。
  • service_assets/{id}/meta.json 中新增 sha256 字段。
  • 后续 POST /api/assets 也可以统一补充哈希,形成服务级去重。

4) 可实时查询指标

新增只读接口:

GET /api/maintenance/storage-summary

返回指标包括:

  • job_dir_count:当前任务目录数。
  • referenced_job_ids:被素材引用的任务数。
  • stale_job_count:可回收任务数。
  • reclaimable_bytes:可回收字节数。
  • jobs_in_db / events_in_db:当前元数据分录数。
  • dry_run_only: true,明确该接口不做删除。

3. 优化后指标

空间收益(只做审计,未执行删除)

指标 优化前 优化后可清理 优化后保留
任务目录 193 187 6(被素材引用)
任务文件占用 2.44 GiB 2.38 GiB ~59.3 MiB
任务空间占用 100% 可回收 97.6% 首个保护区约 2.4%

换算:

  • 2,556,506,642 bytes ≈ 2.38 GiB。
  • 若执行清理,仅任务目录可释放约 2.38 GiB
  • 清理后任务目录可降到约 59.3 MiB,即保留的部分仍是当前贴纸真正引用的任务产物。

素材去重收益

当前 40 个素材文件中有 6 个属于重复内容,去重后:

  • 少存 6 个文件。
  • 可节省 2,455,630 bytes,约 2.34 MiB
  • 素材文件数量从 40 → 34 个唯一内容。

这个数字目前不大,因为很多重复不到 100KB;真正大头仍是任务目录。

效能与可维护性收益

  1. 任务可恢复

    • 原来重启服务后任务状态、进度、事件全部丢失。
    • 现在 jobs / job_events 落库,启动时可恢复。
  2. 查询由全盘扫描变为索引查询

    • 原来 list_jobs 只读内存;任务详情依赖内存里的事件列表。
    • 现在有持久化事件表和 job_id 索引,可追溯历史。
  3. 清理依据可计算

    • 原来“哪个目录能删”靠人工判断。
    • 现在可统计“是否被素材引用、是否在元数据库、目录多老”,避免误删正在使用的任务。
  4. 存储成本上限可控

    • 配合 TTL 清理,后续每新增任务产生的产物会在保留期后被回收。
    • 不会继续无限制累积。

4. 建议后续执行步骤

  1. 确认当前项目不再需要 187 个旧任务产物后,执行:
cd backend
.venv/bin/python -m service.storage_metrics --max-age-days 0 --apply
  1. metadata_store.py 从 SQLite 迁移到 PostgreSQL

    • 安装 SQLAlchemy / asyncpg。
    • docker-compose.yml 增加 PostgreSQL 服务。
    • jobs / job_events / assets / design_documents 迁到 PG。
  2. 把贴纸 tint 从 localStorage 迁到 assets 元数据,并由后端 PATCH /api/assets/{id} 维护。

  3. POST /api/assets 统一补 sha256,实现服务级素材去重。

  4. 增加后台定时清理任务,例如保留 7 天、30 天两档。

5. 相关文件

  • backend/service/metadata_store.py
  • backend/service/job_manager.py
  • backend/service/storage.py
  • backend/service/storage_metrics.py
  • backend/service/app.py
  • docs/DESIGN_DATA_STORAGE_PLAN.md