164 lines
6.0 KiB
Markdown
164 lines
6.0 KiB
Markdown
# 业务数据存储优化与指标报告
|
||
|
||
> 状态:已完成第一阶段可审计代码改造;未执行破坏性清理。
|
||
> 目标:减少无效任务文件、把任务元数据从“内存 + 散落目录 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` 才会删除遗留任务目录。
|
||
- 示例:
|
||
|
||
```bash
|
||
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) 可实时查询指标
|
||
|
||
新增只读接口:
|
||
|
||
```text
|
||
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 个旧任务产物后,执行:
|
||
|
||
```bash
|
||
cd backend
|
||
.venv/bin/python -m service.storage_metrics --max-age-days 0 --apply
|
||
```
|
||
|
||
2. 把 `metadata_store.py` 从 SQLite 迁移到 PostgreSQL:
|
||
|
||
- 安装 SQLAlchemy / asyncpg。
|
||
- `docker-compose.yml` 增加 PostgreSQL 服务。
|
||
- 将 `jobs` / `job_events` / `assets` / `design_documents` 迁到 PG。
|
||
|
||
3. 把贴纸 `tint` 从 localStorage 迁到 `assets` 元数据,并由后端 `PATCH /api/assets/{id}` 维护。
|
||
|
||
4. `POST /api/assets` 统一补 `sha256`,实现服务级素材去重。
|
||
|
||
5. 增加后台定时清理任务,例如保留 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`
|