6.0 KiB
6.0 KiB
业务数据存储优化与指标报告
状态:已完成第一阶段可审计代码改造;未执行破坏性清理。 目标:减少无效任务文件、把任务元数据从“内存 + 散落目录 JSON”提升为“可恢复元数据存储”,并为后续 PostgreSQL 迁移留出接口。
1. 优化前现状
任务存储
- 任务状态 / 事件只存在于
JobManager._jobs内存中,服务重启即丢失。 POST /api/jobs每次提交都会立刻创建service_workspace/{job_id}/input、output和配置文件。- 任务完成后没有 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。 - 建
jobs和job_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;真正大头仍是任务目录。
效能与可维护性收益
-
任务可恢复
- 原来重启服务后任务状态、进度、事件全部丢失。
- 现在
jobs/job_events落库,启动时可恢复。
-
查询由全盘扫描变为索引查询
- 原来
list_jobs只读内存;任务详情依赖内存里的事件列表。 - 现在有持久化事件表和
job_id索引,可追溯历史。
- 原来
-
清理依据可计算
- 原来“哪个目录能删”靠人工判断。
- 现在可统计“是否被素材引用、是否在元数据库、目录多老”,避免误删正在使用的任务。
-
存储成本上限可控
- 配合 TTL 清理,后续每新增任务产生的产物会在保留期后被回收。
- 不会继续无限制累积。
4. 建议后续执行步骤
- 确认当前项目不再需要 187 个旧任务产物后,执行:
cd backend
.venv/bin/python -m service.storage_metrics --max-age-days 0 --apply
-
把
metadata_store.py从 SQLite 迁移到 PostgreSQL:- 安装 SQLAlchemy / asyncpg。
docker-compose.yml增加 PostgreSQL 服务。- 将
jobs/job_events/assets/design_documents迁到 PG。
-
把贴纸
tint从 localStorage 迁到assets元数据,并由后端PATCH /api/assets/{id}维护。 -
POST /api/assets统一补sha256,实现服务级素材去重。 -
增加后台定时清理任务,例如保留 7 天、30 天两档。
5. 相关文件
backend/service/metadata_store.pybackend/service/job_manager.pybackend/service/storage.pybackend/service/storage_metrics.pybackend/service/app.pydocs/DESIGN_DATA_STORAGE_PLAN.md