271 lines
12 KiB
Markdown
271 lines
12 KiB
Markdown
# 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
|
||
```
|
||
|
||
本地 Compose 的 Redis 只作为可重建短效状态 fixture,固定使用
|
||
`--appendonly no --save ""`,且不挂载 `/data` 或命名卷。真实 Redis 8.2 契约可
|
||
通过 `.\scripts\test-redis.ps1` 执行;脚本使用唯一命名空间并在结束时定向清理,
|
||
不执行 `FLUSHDB`。生产环境的 Redis 高可用与持久化策略必须独立评审,不能照搬
|
||
本地 fixture。
|
||
|
||
目标拓扑入口:
|
||
|
||
- 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 继续执行原子 Extract,Provider
|
||
继续刷新 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 协调和短期幂等
|
||
结果;生产环境可使用高可用与受控持久化降低窗口丢失风险,但不把它当长期
|
||
业务档案或备份源。本地 Compose 刻意关闭持久化并且不挂载数据卷。
|
||
- 配置:版本化保存校验通过的不可变 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`,确保唯一键不会把新旧凭据错误合并。
|