131 lines
5.8 KiB
Markdown
131 lines
5.8 KiB
Markdown
# 测试与容量验证策略
|
||
|
||
## 1. 原则
|
||
|
||
- 先证明领域不变量,再证明 Adapter 契约,最后证明跨进程行为。
|
||
- 并发测试必须在 race detector 下运行,不能只依赖单线程示例。
|
||
- 时间、随机、网络、Provider 和存储均通过可替换接口或 fixture 控制。
|
||
- 100,000 QPS 是待验证的集群目标,不以架构图、副本数或短时峰值替代证据。
|
||
- 性能通过与正确性通过相互独立;高 QPS 下出现超卖、重复 Extract 或状态
|
||
回退时,结果一律失败。
|
||
|
||
## 2. 测试分层
|
||
|
||
### 单元测试
|
||
|
||
- Proxy 唯一键、TTL 优先级、状态机和 safety margin。
|
||
- Atomic Capacity 的 Reserve、Commit、Cancel、Release 与幂等错误。
|
||
- Routing first-match 与五种策略。
|
||
- Fetch Success、Empty、Duplicate-only、Error 分类。
|
||
- Backoff、jitter、Retry-After、requestInterval、maxInFlight。
|
||
- Extraction eligibility、partial、allOrNothing、health age、TTL、reserve。
|
||
- 配置严格字段、交叉引用、正则、监听保护和独立计数语义。
|
||
|
||
### 契约测试
|
||
|
||
- Provider 响应模板的大小、超时、函数白名单和解析边界。
|
||
- PostgreSQL `FOR UPDATE SKIP LOCKED` 并发批量提取。
|
||
- Outbox 状态更新、发布与幂等重放。
|
||
- Redis Leader 租约、限流和失联恢复。
|
||
- Snapshot/Delta/ACK/Report 的版本与校验和兼容性。
|
||
- OpenAPI 错误模型、认证矩阵、批量 fulfillment。
|
||
|
||
### 集成与端到端
|
||
|
||
- HTTP 正向代理成功、上游连接前失败和安全重试。
|
||
- HTTPS CONNECT 建立后不透明重放。
|
||
- Controller Fetch -> Check -> AVAILABLE -> Worker Snapshot -> Gateway 转发。
|
||
- Distribution 原子提取后 Gateway 不再分配同一 Proxy。
|
||
- 配置热更新失败保留旧 Revision,成功后新请求使用新 Snapshot。
|
||
|
||
## 3. 必测的 11 类场景
|
||
|
||
1. **并发容量**:1000 协程争用同一 Proxy,始终满足
|
||
`active + reserved <= effectiveMaxConcurrency`。
|
||
2. **Reservation 生命周期**:Dial 成功/失败、超时、取消和重复 Release 均不
|
||
泄漏或产生负计数。
|
||
3. **singleflight**:100 个缺池信号只产生一个有效 Fetch 调度。
|
||
4. **Provider 限流**:requestInterval、maxInFlight、timeout、重试和 429
|
||
`Retry-After` 在虚拟时钟下准确。
|
||
5. **Fetch 分类**:Error 不动 Empty;合法空响应 Empty++;duplicate-only
|
||
重置 Empty;Success 重置 Empty。
|
||
6. **Sequential 竞态**:达到阈值时多协程只能将 A 切到 B 一次,不能越过 B。
|
||
7. **Drain**:切换或禁用 Upstream 后停止新分配,已有连接完成后才回收。
|
||
8. **Extract 竞态**:多个请求并发提取同一候选集合,每个 Proxy 最多返回一次。
|
||
9. **Extract 批量语义**:partial 提交实际数量;allOrNothing 不足时状态和审计
|
||
全回滚;始终保留 `reserveForGateway`。
|
||
10. **Worker ownership**:回收过程严格经过 DRAINING、ACK、active/reserved=0、
|
||
unowned,旧 Snapshot 不可再分配。
|
||
11. **控制面故障**:Redis、PostgreSQL、Controller、Checker 与 Provider 分别
|
||
失效时,行为与 Runbook 一致,Gateway 热路径不被同步依赖拖垮。
|
||
|
||
## 4. 测试命令
|
||
|
||
所有后台测试都设置 60 秒上限:
|
||
|
||
```powershell
|
||
go test -timeout 60s ./...
|
||
go test -timeout 60s -race ./internal/...
|
||
go vet ./...
|
||
go build ./...
|
||
```
|
||
|
||
需要 PostgreSQL/Redis 的测试使用独立数据库和短生命周期容器,不复用开发数据。
|
||
测试结束后验证没有残留 Worker ownership、Leader 租约或未提交 Extraction Record。
|
||
|
||
## 5. 负载模型
|
||
|
||
必须分开运行,避免不同瓶颈互相掩盖:
|
||
|
||
### HTTP QPS
|
||
|
||
- GET/HEAD 占比、响应体大小、Keep-Alive 复用率与生产预测一致。
|
||
- 依次运行 10k 稳态、阶梯升压和 100k 峰值。
|
||
- 同时记录端到端与 Gateway 内部 Dispatch 延迟。
|
||
|
||
### CONNECT
|
||
|
||
- 分开测试活跃隧道数和每秒新建隧道数。
|
||
- 包含短连接、长连接、半关闭、Client 取消和上游主动断开。
|
||
- 验证 200 已发送后不发生透明重放。
|
||
|
||
### Snapshot
|
||
|
||
- 1k、10k、100k Proxy Snapshot,测构建、校验、原子切换、内存峰值和 GC。
|
||
- 在满负载下发布 Snapshot,确认请求线程不参与索引构建。
|
||
|
||
### Extract
|
||
|
||
- 小批 partial、大批 allOrNothing、高冲突 filter 和库存不足。
|
||
- 与 Gateway 同时运行,持续检查 `reserveForGateway` 和无重复返回。
|
||
|
||
### 故障负载
|
||
|
||
- 负载运行中断开 Controller、Redis、PostgreSQL、一个 Worker 和一个可用区。
|
||
- Provider 注入 DNS、超时、500、429、超大响应、模板错误和合法空响应。
|
||
- Checker 注入慢目标与队列积压。
|
||
|
||
## 6. 通过条件
|
||
|
||
业务 SLO 由产品最终确认,但至少满足以下工程门槛:
|
||
|
||
- 无容量超卖、负计数、重复 Extract、审计缺失或状态非法回退。
|
||
- 100k 峰值期间无进程 OOM、FD 耗尽、无界队列或全局锁热点。
|
||
- Gateway 热路径在 PostgreSQL、Redis、Provider 失效时不发起同步访问。
|
||
- p99 Dispatch 小于 100 微秒的设计预算需要在 100k Proxy Snapshot 下单独证明。
|
||
- 最大故障域丢失后,剩余容量仍满足约定 SLO;否则增加副本或降低承诺容量。
|
||
- Snapshot 超过 `maxStaleAge` 后 Gateway 拒绝新流量,已有连接按时排空。
|
||
- 所有数据、命令、Git SHA、镜像 digest、环境和原始指标可以复现。
|
||
|
||
## 7. 测试报告模板
|
||
|
||
```text
|
||
版本:Git SHA / image digest / Go version
|
||
环境:节点、CPU、内存、NIC、内核、Kubernetes/CNI
|
||
配置:Snapshot 规模、Proxy 容量、路由、重试、日志级别
|
||
场景:协议、连接复用、响应体、持续时间、升压曲线、故障注入
|
||
结果:QPS、建连速率、active、p50/p95/p99、错误、CPU、RSS、GC、FD、网络
|
||
不变量:capacity、ownership、extraction、audit、reserve 检查结果
|
||
结论:通过/失败,以及适用边界
|
||
```
|