Files
orbit/docs/19-capacity-model.md

132 lines
7.3 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.
# Orbit 容量模型与验收方法
版本:0.1 · 2026-09-20
状态:容量推导方法;不是生产容量结论
本文把“企业数量”转换为可测的任务、流程、事件、连接和数据库负载。所有示例数字都是演算用假设,不能直接作为上线承诺。生产容量必须用目标硬件、目标 MySQL 拓扑、实际保留周期和隔离业务数据重新测量。
## 1. 输入参数
容量评估至少固定下面这些输入,并将它们保存到每次负载报告的环境 JSON 中:
| 符号 | 含义 | 说明 |
| --- | --- | --- |
| `E` | 企业总数 | 用于规模推导,不等于连接数或队列数 |
| `a` | 日活跃企业比例 | 0 到 1,按实际业务日历取值 |
| `t` | 每个活跃企业每日提交任务数 | 任务提交和计划触发分开统计 |
| `B` | 每日业务窗口秒数 | 夜间批处理必须单独建峰值窗口 |
| `p` | 峰值放大倍数 | 由历史曲线或集中业务窗口确定 |
| `d` | 一次任务平均执行秒数 | 同时提供 p50/p95/p99,不用单一平均值替代长尾 |
| `r` | 平均总尝试次数 | 包含自动重试,不包含人工关联新任务,后者单独计数 |
| `s` | 每个任务产生的持久化事件数 | Pulse、Weave、结果交付分别统计 |
| `h` | 平均任务/结果/事件有效字节数 | 只计业务字段,索引和页开销另加 |
| `R` | 保留天数 | 幂等、审计、执行历史、结果交付不能共用一个未经评审的周期 |
| `c` | 每个 Worker 连接的有效并发 | 由容量、心跳、续租和处理器延迟共同决定 |
还要记录流程实例数、每实例步骤数、并行度、等待实例比例、信号速率、定时计划数、触发分布、查询轮次和外部请求峰值。单独记录 `E` 而不记录这些输入,不能推出服务器规格。
## 2. 基础推导
每日可靠受理量为:
```text
Qday = E × a × t
```
业务窗口内的平均受理速率和设计峰值为:
```text
λavg = Qday / B
λpeak = λavg × p
```
任务执行并发的近似下界为 Little 定律:
```text
Wactive ≈ λpeak × d
```
实际容量还要加上租约续租、重试、流程内部任务、定时集中触发和恢复补偿的余量。应分别计算:
```text
Wtotal = Wbusiness + Wretry + Wworkflow + Wschedule + Wrecovery
```
Worker 数量的初步估计为:
```text
Nworker ≥ ceil(Wtotal / c) × safety_factor
```
`safety_factor` 只是规划余量,不能替代节点故障、滚动升级和积压清空实验。Worker 的连接数应按 `Nworker × 每实例连接数` 计算,并与 MySQL 最大连接、服务端连接池和 WebSocket 文件描述符上限分别核对。
## 3. 数据库写放大与存储
任务量不是数据库写入量。每个任务至少可能涉及任务主记录、幂等身份、尝试、执行历史、状态事件、审计和结果交付;Weave 还会增加实例、步骤、等待、信号、内部结果和时间线记录。应按实际状态路径统计行数:
```text
RowsPerTask = task_rows + idempotency_rows + attempt_rows × r
+ event_rows × s + audit_rows + delivery_rows
```
每日新增行数和保留期行数为:
```text
RowsDay = Qday × RowsPerTask + schedule_rows + workflow_rows + inbox_rows
RowsRetention = RowsDay × R
```
存储估算至少拆分数据页、二级索引、Undo/Redo、临时空间、备份和复制日志:
```text
DataBytes ≈ RowsRetention × (h + row_overhead + index_overhead)
```
`row_overhead` 和 `index_overhead` 必须从目标 MySQL 版本的真实表、索引和字符集测得。不能用 Go 结构体大小或 JSON 字符串长度替代 InnoDB 页空间。未知效果、未确认交付、未终结流程和审计记录不能为了缩小容量而提前清理。
## 4. 演算示例(非验收)
下面只说明推导方法:假设 `E=1,000,000`、`a=0.10`、`t=20`、`B=36,000` 秒、`p=6`,则:
```text
Qday = 2,000,000 个任务/日
λavg ≈ 55.6 个任务/秒
λpeak ≈ 333.3 个任务/秒
```
如果一次任务平均总执行时间为 2 秒,单看业务任务会得到约 667 个同时执行任务;若重试、流程、定时和恢复再增加 60% 的并发余量,则规划值约为 1,067。这个结果只用于确定下一轮实验规模,不能推出节点数量、MySQL 规格或可用性。
若每个任务路径暂按 8 行、每行数据及索引平均 2 KiB 的假设演算,30 天会得到约 480,000,000 行、约 916 GiB(约 983 GB 十进制)的逻辑页空间;该假设对实际 JSON、索引、压缩、历史和业务结果极其敏感,必须以真实采样替换。
## 5. 测试矩阵
每个目标版本至少执行以下六组,并保存参数、源码/二进制哈希、MySQL 版本、拓扑和资源曲线:
1. **短任务基线**:空处理器或固定极短处理器,测框架受理、排队、派发和完成开销。
2. **混合执行**:短、中、长任务按生产比例混合,包含续租和有限重试。
3. **集中触发**:定时计划在同一窗口到期,核对触发唯一性、计划进度和积压。
4. **流程推进**:顺序、分支、有限并行、等待和信号混合,逐个核对内部任务、结果和版本。
5. **长期积压**:固定 Worker/容量下持续输入,记录等待曲线、锁等待、磁盘、内存和积压清空时间。
6. **故障恢复**:服务节点、Worker、WebSocket、数据库连接在不同切点退出,记录重新授权、未知结果、恢复扫描和数据核对时间。
负载工具使用 [任务执行测量](api/execution-load.md)、[流程测量](api/workflow-load.md) 和 [定时测量](api/schedule-load.md)。每组都要记录 p50/p95/p99、成功和未核验分母;任何截止或资源不足导致的未核验项都不能计入成功吞吐。
## 6. MySQL 与部署边界
- 状态转换、幂等提交、租约和恢复以 MySQL 主库为权威;只读副本不能承载需要最新状态的核对或控制操作。
- 复制确认、主从切换、RPO/RTO、备份介质和跨故障域部署必须在目标拓扑实测。一次性单节点容器只证明功能和故障注入逻辑。
- 服务端节点可以横向扩展,但必须测量锁等待、扫描批次、连接池、复制延迟和节点间重连;多节点数量不能从单节点吞吐线性外推。
- 不引入 Redis、消息队列或独立协调服务作为容量假设。若未来改变依赖范围,必须重新评审数据权威、故障边界和运维责任。
## 7. 通过条件
容量报告只有同时满足下面条件,才能进入生产发布评审:
- 目标峰值下,受理、派发、流程推进和结果交付的 p99 在已批准的延迟预算内;
- 故障组仍保持幂等、审计、未知效果核查和可恢复,未核验项有明确处置;
- 数据库 CPU、锁等待、连接、磁盘、Redo/Undo、复制滞后和备份窗口均保留经评审的余量;
- 节点滚动升级、单节点故障和主库切换后的积压能在批准的恢复窗口内清空;
- 负载和故障结果绑定不可变提交、工具链、迁移版本和参数,报告中明确未覆盖项。
当前仓库已有隔离单节点样本和 Go 1.27.1 的可运行场景证据,但没有目标硬件、复制切换或百万企业规模的生产容量结论;这些项目仍见 [生产验收](05-production-acceptance.md) 和 [首版交付清单](release-checklist.md)。