Files
wordcloud/docs/DATA_STORAGE_OPTIMIZATION.md
T

164 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 业务数据存储优化与指标报告
> 状态:已完成第一阶段可审计代码改造;未执行破坏性清理。
> 目标:减少无效任务文件、把任务元数据从“内存 + 散落目录 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`