docs(传输): 补一期实施与本地实测记录

监听周期实测精确 5.00 秒触发、空目录单轮 8-13ms;md5 索引在 23 行下
规划器仍选顺序扫描(正确行为),关掉后走 Index Scan 证明索引可用;
容器内 I/O 基准(同镜像同 bind mount,真实 23 个文件 19.04MB)测得
缓冲区改造 8.2 倍、叠加 level 0 共 17.6 倍,包体 +5.1%。

据实修正第 3.4 节的预测偏差:31 倍是纯 I/O 理论值,缓冲改完后 deflate
CPU 占到剩余耗时的一半,对外口径改用实测的 8 倍/17 倍。
另记录尚未验证的部分(应用内真实组包、解包侧、level 0 往返、现场系数)。
This commit is contained in:
KodouWZF
2026-11-03 22:22:27 +08:00
parent 456b1ea62d
commit 75ab51e13c

View File

@@ -1,8 +1,9 @@
# 跨网传输链路性能优化方案 # 跨网传输链路性能优化方案
> 版本:v1.0(2026-11-03) > 版本:v1.1(2026-11-03)
> 适用后端:s-file(alita-bjy-uygur) > 适用后端:s-file(alita-bjy-uygur)
> 状态:待评审 → 待实施 → 待现场验证 > 状态:一期(5.1/5.3/5.4/5.5)已实施并本地验证 → 待现场验证;二期(5.2)待实施
> 实施与实测记录见第 10 节
> 关联代码:`TransferUserFileServiceImpl`(发送/组包)、`TransferFileMonitorServiceImpl`(接收/解包)、`TransferFileMonitorJob`(调度)、`FileServiceImpl` / `LocalFileStorage`(物理文件读写) > 关联代码:`TransferUserFileServiceImpl`(发送/组包)、`TransferFileMonitorServiceImpl`(接收/解包)、`TransferFileMonitorJob`(调度)、`FileServiceImpl` / `LocalFileStorage`(物理文件读写)
--- ---
@@ -408,3 +409,80 @@ CREATE INDEX idx_file_record_md5_code ON xs_file_record(md5_code);
建议 1–4 作为一期(都是低风险、可独立验证的改动),5 作为二期,6 视现场文件大小分布决定。 建议 1–4 作为一期(都是低风险、可独立验证的改动),5 作为二期,6 视现场文件大小分布决定。
**每一项都必须单独验证并记录数字**,不要合并提交,否则现场出问题时无法定位是哪一项引起的。 **每一项都必须单独验证并记录数字**,不要合并提交,否则现场出问题时无法定位是哪一项引起的。
---
## 10. 一期实施与验证记录(2026-11-03,本地环境)
一期 4 项已实施,每项独立提交:
| 项 | 提交 | 内容 |
|---|---|---|
| 5.3 | `4114c1f` | 组包/解包/落盘缓冲区 512B、8KB → 64KB,共 5 处 |
| 5.1 | `06fb35b` | 监听周期 `0 */1 * * * ?` → `0/5 * * * * ?`,Java 默认值 + 4 个部署文件 |
| 5.5 | `c5d19f4` | `idx_file_record_md5_code`,init 双库 + upgrade 脚本 + 交付包副本 |
| 5.4 | `456b1ea` | 按后缀对已压缩格式用 `Deflater.NO_COMPRESSION` |
编译:JDK 8 + `mvn package -Dmaven.test.skip=true`,BUILD SUCCESS。
(`-DskipTests` 不行:surefire 2.22.2 的传递依赖 `plexus-utils:1.1` 本地仓库没有,离线模式解析失败,需联网补一次。)
### 10.1 5.1 监听周期 — 已实测通过
重启后从 `sfile-iw-app` 日志读 `AlitaStopWatchAspect` 输出:
```
22:14:05.128 TransferFileMonitorJob.execute(),use(ms): 127 ← 首轮预热
22:14:10.028 TransferFileMonitorJob.execute(),use(ms): 13
22:14:15.013 TransferFileMonitorJob.execute(),use(ms): 12
22:14:20.025 TransferFileMonitorJob.execute(),use(ms): 13
22:14:25.015 TransferFileMonitorJob.execute(),use(ms): 13
22:14:30.024 TransferFileMonitorJob.execute(),use(ms): 11
22:14:35.003 TransferFileMonitorJob.execute(),use(ms): 8
```
- 触发间隔精确 5.00 秒,cron 表达式合法,应用启动无异常
- **空目录单轮 8–13 ms**,即每分钟约 150 ms 的开销,证实 5.1 中「空目录扫描开销可忽略」的判断
- 两侧轮询空等从平均 60 秒降到平均 5 秒
### 10.2 5.5 md5 索引 — 已实测通过
两个本地库(`sfile-iw-pg`、`sfile-ow-pg`)执行 upgrade 脚本均成功,脚本可重复执行(第 2 节 `IF NOT EXISTS` 生效)。
`EXPLAIN SELECT * FROM xs_file_record WHERE md5_code='ABC' AND deleted=FALSE LIMIT 1`:
- 默认:**Seq Scan**(当前 23 行,规划器判断顺序扫描更便宜,这是正确行为,也印证 5.5 中「数据量小时收益不可见」)
- `SET enable_seqscan=off` 后:**Index Scan using idx_file_record_md5_code** → 索引有效可用,数据量上来后会自动切换
### 10.3 5.3 + 5.4 缓冲区与压缩级别 — 已实测通过(容器内 I/O 基准)
端到端发送需要登录,本地 admin 口令未知,因此改用**容器内 I/O 基准**直接测量组包环节:复刻 `packTransferFiles` 的读写形态,在同一个 `sfile-app:local` 镜像、同一份 bind mount 上跑真实的 23 个文件(19.04 MB,即线上样本目录 `iw/upload/1`)。
必须在容器内测——syscall 放大来自容器到宿主机的文件共享层,在宿主机上直接测不出这个成本。
3 轮结果(每轮依次跑三种方式,输出 zip 随即删除):
| 方式 | 第 1 轮 | 第 2 轮 | 第 3 轮 | 产出大小 |
|---|---|---|---|---|
| 旧:512B 出 / 8KB 读,level 6 | 9033 ms | 8279 ms | 9701 ms | 18.12 MB |
| 新:64KB 出 / 64KB 读,level 6 | 1022 ms | 1109 ms | 1115 ms | 18.12 MB |
| 新:64KB 出 / 64KB 读,level 0 | 516 ms | 491 ms | 509 ms | 19.04 MB |
- **5.3 单独收益:约 8.2 倍**(9033 → 1022 ms)
- **5.3 + 5.4 合计收益:约 17.6 倍**(9033 → 509 ms)
- level 0 让包体从 18.12 MB 变成 19.04 MB(**+5.1%**)。反过来说明这个样本里 level 6 只压掉了 5%,即内容基本已是压缩格式——**用 5% 的体积换一半的时间,划算**
#### 与第 3.4 节预测的偏差(需据实修正)
| 项 | 预测 | 实测 | 说明 |
|---|---|---|---|
| 每 MB 组包成本(旧) | 2.33 s/MB(应用日志基线) | **0.47 s/MB**(基准 old 模式) | 基线 45.9 秒那次是在不同负载/冷缓存下采的;基准跑前已有预热。两者都是真实的,差异来自环境状态 |
| 提速倍数 | 31× | **8.2×**(level 6)/ **17.6×**(level 0) | 31× 是纯 I/O 的理论值。实测 new-l6 的 1022 ms 里约 500 ms 是 deflate CPU(因为 new-l0 只要 509 ms),缓冲改完后 CPU 占比升到一半,总倍数自然低于纯 I/O 倍数 |
**结论:预测方向正确、量级偏高。** 现场汇报口径建议用实测的 **8 倍(仅改缓冲)/ 17 倍(含 level 0)**,不要用 31 倍。第 3.4 节的表格在现场按 4.2 的系数重算后再对外给数。
### 10.4 尚未验证的部分
- [ ] **应用内真实组包**:需要登录后发送一次同一个文件夹,从 `ControllerLogAspect` 的 `useTime` 与「传输文件打包完成」日志确认应用侧数字(基准只覆盖 I/O 环节,未含 SQL 与元数据序列化)
- [ ] **解包侧**:64KB `ZipInputStream` 的改动只做了编译验证,未跑通一次真实解包(同样受登录限制)
- [ ] **level 0 产出的 zip 能否被接收端正常解包**:需一次内穿外 + 一次外传内的完整往返
- [ ] **现场系数**:客户环境是 Linux + 光闸监控目录,syscall 单价与本地 Docker Desktop 不同,必须按第 4 节重测