proxy-pool/docs/operations/runbook.md
youfak 4de3ffb85f
Some checks are pending
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
feat: add ephemeral proxy activity pool
2026-07-29 12:51:18 +08:00

264 lines
12 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.

# Proxy Pool 运维手册
## 1. 运行边界
- Gateway 是数据面,正常请求热路径不访问 PostgreSQL、Redis 或 Provider。
- Controller 编排 Fetch、生命周期、所有权、Snapshot 与 Extract多个副本只有
一个 Provider 逻辑 Leader。短效 Proxy 明细只存在于 Redis TTL 活动池和节点
内存,可由 Provider 重建。
- PostgreSQL 只持久化配置版本、Upstream/Routing 管理状态、Admin 审计与
outbox以及可选聚合指标不保存 Proxy 明细或逐次提取记录。
- Checker 执行有界健康探测,只上报 Observation最终状态由 Controller
reducer 决定。
- Extract 是一次性独占发放。Redis 在单次原子操作中校验并从可分配活动池移除
候选,同时写入带 TTL 的幂等结果;没有 Lease、续租或 Release 接口。
- `reserveForGateway` 是共享池硬约束Extract 不得把 Gateway 库存清空。
- 集群峰值 100,000 QPS 是设计目标,只有完成本文容量验收后才能作为已验证
能力对外承诺。
## 2. 本地拓扑模板
当前仓库交付设计、契约、部署拓扑和关键领域实现;`cmd/proxy-*` 的完整运行时
装配属于 `implementation-plan.md` 后续任务。此处 Compose/Kubernetes 资产用于
评审网络、资源、探针和依赖关系,当前只执行静态渲染,不把模板写成可运行服务。
### 2.1 前置条件
- Docker Engine 25+Compose v2.30+。
- 至少 8 CPU、16 GiB 内存和 20 GiB 可用磁盘。
- 本地端口 `3000`、`8080`、`8081`、`8082`、`8404`、`9091` 未占用。
### 2.2 配置凭据
`deploy/config/local.yaml` 只用于本机拓扑验证。进入运行时实施阶段后,再通过
密钥系统提供下列变量,并把 Provider 地址替换为测试 fixture
```powershell
$env:PROXY_POOL_GATEWAY_PASSWORD = "LOCAL_GATEWAY_PASSWORD"
$env:PROXY_POOL_EXTRACT_TOKEN = "LOCAL_EXTRACT_TOKEN"
$env:PROXY_POOL_ADMIN_TOKEN = "LOCAL_ADMIN_TOKEN"
$env:PROVIDER_A_TOKEN = "PROVIDER_A_TOKEN"
$env:PROVIDER_B_TOKEN = "PROVIDER_B_TOKEN"
```
### 2.3 静态检查
```powershell
docker compose -f deploy/docker-compose.yml config
kubectl kustomize deploy/kubernetes/base > rendered.yaml
```
目标拓扑入口:
- Gateway`127.0.0.1:8080`
- Distribution`http://127.0.0.1:8081`
- Admin`http://127.0.0.1:8082`
- HAProxy 状态:`http://127.0.0.1:8404/stats`
- Prometheus`http://127.0.0.1:9091`
- Grafana`http://127.0.0.1:3000`
`deploy/config/local.yaml` 中的 `.invalid` Provider 是故障演示占位。未替换时
Fetch 应表现为 Error 与退避,不应增加 Empty 计数,也不影响已有 Proxy。
## 3. Kubernetes 发布
本节是运行时实施完成后的发布规格,不代表当前代码已达到生产就绪。
### 3.1 准备
1. 使用托管 PostgreSQL 和 Redis分别配置 TLS、备份、监控和多可用区。
2. 复制 `secret.example.yaml` 到环境私密配置系统,由 External Secrets、SOPS
或密钥管理平台生成 `proxy-pool-secrets`,不要提交真实 Secret。
3. 在环境 Overlay 替换镜像、Provider 地址、允许网段、外部存储地址、资源量
和 LoadBalancer 注解。
4. 根据集群 CNI 能力收紧 NetworkPolicy 的外部网段。
5. 在预发布环境完成数据库向前兼容迁移,再发布 Controller。
### 3.2 服务端应用顺序
```bash
kubectl apply -f deploy/kubernetes/base/namespace.yaml
kubectl -n proxy-pool apply -f ENVIRONMENT_SECRET.yaml
kubectl apply -k deploy/kubernetes/base
kubectl -n proxy-pool rollout status deployment/proxy-controller --timeout=5m
kubectl -n proxy-pool rollout status deployment/proxy-checker --timeout=5m
kubectl -n proxy-pool rollout status deployment/proxy-gateway --timeout=10m
```
### 3.3 探针语义
- `/livez`:进程事件循环仍可运行。数据库或 Redis 短暂失败不得导致 Gateway
liveness 失败。
- `/readyz`进程可以接收新工作。Gateway 只有在持有未超过 `maxStaleAge`
的完整 Snapshot 且仍有准入能力时才 Ready。
- Controller 按能力判定就绪Distribution/Fetch 依赖 Redis 活动池Admin 持久化
写依赖 PostgreSQL 与兼容迁移。PostgreSQL 故障不得单独使 Extract 返回 503。
- Checker 在任务消费与结果上报通道可用时 Ready。
- `/metrics`独立于业务入口NetworkPolicy 仅允许监控命名空间访问。
探针不得执行 Provider 请求或完整数据库扫描。
### 3.4 发布顺序与兼容性
1. 先做向前兼容数据库迁移。
2. 发布 Controller确认旧 Worker 仍能消费旧 Snapshot 协议版本。
3. 发布 Checker。
4. 逐批发布 Gateway每次至少保留 PDB 要求的健康副本。
5. 观察 30 分钟,再清理已经无人读取的旧字段或旧迁移。
回滚只能回到仍兼容当前 Schema 和 Snapshot 版本的镜像。涉及不可逆数据迁移时,
必须使用前向修复。
## 4. 容量规划
```text
worker_replicas =
ceil(peak_qps / (tested_worker_qps * target_utilization))
+ largest_failure_domain_replicas
```
- `peak_qps`:当前目标为 100,000。
- `tested_worker_qps`:在同 CPU、内存、网络、Go 版本、Snapshot 规模、TLS 与
上游响应模型下测出的单 Pod 持续能力。
- `target_utilization`:不高于 0.60给突发、GC 和故障转移留空间。
- `largest_failure_domain_replicas`:最大单可用区失效时丢失的副本数。
禁止用 CPU 核数直接推算 QPS也禁止把短时峰值当持续容量。Kubernetes 基线的
6 个 Gateway 副本只是初始值,必须由压测结果调整。
HPA 使用 CPU/内存作为保护性信号;生产环境建议通过 Prometheus Adapter 加入:
- 每 Pod Gateway QPS。
- 活跃连接数和建连速率。
- p99 Dispatch 延迟。
- 拒绝率和 Available Slots。
连接型工作负载缩容至少稳定 10 分钟,终止前先 NotReady再等待现有隧道排空。
## 5. 日常检查
每班次检查:
1. Gateway QPS、错误率、p95/p99 和活跃连接。
2. Snapshot age、epoch/version、重同步与 ACK 延迟。
3. Available Slots、Reserved、Active、各 Proxy 状态数量。
4. Provider Success、Empty、Duplicate-only、Error、429 与退避。
5. Checker 队列、SUSPECT 数、检查延迟和目标级失败。
6. Extract requested/returned、insufficient、冲突和幂等命中。
7. PostgreSQL 连接、管理事务失败、outbox backlog、WAL 与备份。
8. Redis 延迟、内存、TTL 淘汰、原子操作错误、主从状态和 Leader 租约抖动。
Prometheus 标签禁止包含 Proxy IP、Client ID、Session、完整 URL、request ID。
需要逐请求调查时使用受控、脱敏且采样的结构化日志。
## 6. 优雅停机
### Gateway
1. readiness 立即失败,停止新连接。
2. 停止应用新 Snapshot但保留当前不可变版本。
3. 等待 HTTP 请求和 CONNECT 隧道排空。
4. 到达 60 秒上限后关闭残余连接,保证容量 reservation 被释放。
### Controller
1. 停止接收新的 Extract/Admin 写请求。
2. 停止发起 Fetch释放 Provider Leader 租约。
3. 等待已提交 Redis 原子操作返回;未确认请求的客户端必须使用相同幂等键重试。
4. 刷新 Admin outbox、审计和 Worker ACK再关闭 PostgreSQL/Redis 连接池。
### Checker
1. 停止领取新任务。
2. 在 45 秒内完成或取消现有探测。
3. 批量上报已完成 Observation未完成任务由队列重新投递。
## 7. 故障处置
### 7.1 Snapshot 陈旧
症状:`ProxyPoolGatewaySnapshotStale`、Worker 重同步增加、Gateway Ready 下降。
1. 检查 Controller、控制流和 outbox 延迟。
2. 确认 Worker epoch 与 Controller epoch禁止手工降低 epoch。
3. 缺版本时强制完整 Snapshot不要继续应用 Delta。
4. `maxStaleAge` 内允许旧 Snapshot 服务;超限自动拒绝新流量并排空。
5. 不得通过无限增大 `maxStaleAge` 隐藏控制面故障。
### 7.2 PostgreSQL 不可用
1. Gateway 继续使用最后有效 Snapshot。
2. Redis 健康且运行配置有效时Distribution 继续执行原子 ExtractProvider
继续刷新 TTL 活动池。
3. 拒绝配置版本、Upstream/Routing 管理状态和其他需要 Admin 审计/outbox 的写入;
不得把 Proxy 明细临时落入 PostgreSQL。
4. 恢复后核对迁移、管理事务回滚、Admin 审计与 outbox backlog不存在 Proxy
明细或逐次提取记录恢复步骤。
### 7.3 Redis 不可用
1. Gateway 继续读取节点内最后有效 Snapshot直到 `maxStaleAge`;请求热路径不
回查 PostgreSQL 或 Provider。
2. Distribution 立即失败关闭并返回 503禁止本地内存提取或 PostgreSQL 兜底。
3. Controller 停止活动池写入和需要分布式互斥的工作,防止多个 Fetch Leader
本地限流不能声称满足全局额度。
4. 恢复后确认 Leader 唯一和租约 epoch 单调,由 Provider 重新 Fetch 并构建 TTL
活动池,再恢复 Distribution。Redis 整体丢失会终止原活动池代次的排他状态和
短期幂等窗口;高可用、持久化、监控和告警必须明确并降低该风险。
### 7.4 Provider 故障
1. 超时、DNS、认证、非预期 HTTP、响应超限与模板错误全部计 Error。
2. 429 尊重 `Retry-After`,其余 Error 使用指数退避和 jitter。
3. Error 不增加 Empty合法候选为零才增加 Empty。
4. Duplicate-only 重置 Empty 并记录独立指标。
5. 达到 Empty 阈值后每条受影响 Routing 只原子切换一次。
### 7.5 Gateway 容量耗尽
1. 检查 Available Slots而不是只看 Proxy 数量。
2. 确认是否大量容量停留在 Reserved排查 Commit/Cancel 泄漏。
3. 检查 TTL safety margin、健康状态和 Worker 所有权是否导致候选被过滤。
4. 快速拒绝新请求,禁止无界等待或把压力转移到 Controller。
5. 扩容 Gateway 前确认存在可分配 Proxy 所有权切片。
### 7.6 Extract 库存不足
1. `partial` 返回实际数量;`allOrNothing` 不足时不改变 Redis 活动池。
2. 检查 TTL、health age、filter、Worker ownership 和 `reserveForGateway`
3. 不得降低 `reserveForGateway` 到导致 Gateway 容量告警的水平。
4. 回收 Worker-owned Proxy 必须先 DRAINING、等待 active/reserved 为零、清除
ownership再由 Redis 原子操作将其从可分配活动池移除并写入短期幂等结果。
5. 已提取代理没有 Release客户端归还请求只记录为无效调用不恢复库存。
### 7.7 Checker 积压
1. 优先新 Proxy 与 SUSPECT 复检。
2. 降低稳定 AVAILABLE 的普通复检频率。
3. 检查目标超时、DNS 与出口网络,再按任务延迟扩容 Checker。
4. 队列必须有上限;不得无限积压耗尽内存或 Redis。
## 8. 备份与恢复
- PostgreSQL每日全量、连续 WAL/PITR保护配置版本、Upstream/Routing 管理
状态、Admin 审计与 outbox至少每季度做恢复演练。
- Redis保存可由 Provider 重建的 TTL 活动池、所有权/Leader 协调和短期幂等
结果;使用高可用与持久化降低窗口丢失风险,但不把它当长期业务档案。
- 配置:版本化保存校验通过的不可变 Revision 与校验和。
- Secret由密钥平台版本化日志和备份中不得出现明文。
管理面恢复顺序PostgreSQL -> Controller/Admin代理运行面恢复顺序Redis ->
Provider 重建活动池 -> Controller/Checker -> 发布新 Snapshot。验证 Worker
ownership epoch、活动池 TTL、短期幂等窗口、outbox 和配置 Revision 一致后,再
开放相应能力Gateway 在旧 Snapshot 未超过 `maxStaleAge` 时无需等待数据库恢复。
## 9. Secret 轮换
1. 创建新 Secret 版本,不覆盖旧值。
2. Provider/API 凭据支持双版本重叠时先发布新版本。
3. 更新配置 Revision确认 Controller 成功重建 Adapter。
4. 观察 Fetch Error、认证失败与 Snapshot ACK。
5. 所有副本应用后撤销旧 Secret。
Proxy 凭据轮换必须增加 `credentialVersion`,确保唯一键不会把新旧凭据错误合并。