14 KiB
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-controller 已完成配置单次加载、PostgreSQL 迁移、Redis 活动池、
Distribution/Admin/Metrics 独立监听和有界停机装配。Provider 自动补池、业务
指标以及 Gateway/Checker/Loadgen 三个进程仍属于 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:
$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 静态检查
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。
PostgreSQL 管理面集成测试通过 .\scripts\test-postgres.ps1 启动
postgres:18-alpine,仅绑定 127.0.0.1:15432,并将 PG18 数据根目录挂载为
tmpfs。ApplyMigrations 在同一物理连接上执行仓库内嵌的幂等前向迁移;测试为
每个契约创建唯一 Schema,结束时只删除该 Schema 和临时 Compose 项目。该脚本
禁止指向开发或生产数据库。
.\scripts\test-controller.ps1 同时启动两个隔离 fixture,验证 Controller
bootstrap 的迁移、启动配置提交、Redis Readiness、Admin Status、/readyz 与
Prometheus 输出。脚本不启动
部署模板中的 Controller 容器,也不连接开发或生产存储。
目标拓扑入口:
- Gateway:
127.0.0.1:8080 - Distribution:
http://127.0.0.1:8081 - Admin:
http://127.0.0.1:8082 - Controller Metrics:
http://127.0.0.1:9090 - 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 准备
- 使用托管 PostgreSQL 和 Redis,分别配置 TLS、备份、监控和多可用区。
- 复制
secret.example.yaml到环境私密配置系统,由 External Secrets、SOPS 或密钥管理平台生成proxy-pool-secrets,不要提交真实 Secret。 - 在环境 Overlay 替换镜像、Provider 地址、允许网段、外部存储地址、资源量 和 LoadBalancer 注解。
- 根据集群 CNI 能力收紧 NetworkPolicy 的外部网段。
- 在预发布环境完成数据库向前兼容迁移,再发布 Controller。
3.2 服务端应用顺序
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。
- 同一 Controller 同时启用 Distribution 与 Admin 时,Pod
/readyz以 Redis 活动池为服务流量门槛;PostgreSQL 故障由 Admin 接口独立返回不可用,不把仍可 完成的 Extract 从 Service 摘除。Admin-only 进程才同时检查 PostgreSQL 与 Redis。 - Checker 在任务消费与结果上报通道可用时 Ready。
/metrics:独立于业务入口,NetworkPolicy 仅允许监控命名空间访问。
探针不得执行 Provider 请求或完整数据库扫描。
3.4 发布顺序与兼容性
- 先做向前兼容数据库迁移。
- 发布 Controller,确认旧 Worker 仍能消费旧 Snapshot 协议版本。
- 发布 Checker。
- 逐批发布 Gateway;每次至少保留 PDB 要求的健康副本。
- 观察 30 分钟,再清理已经无人读取的旧字段或旧迁移。
迁移失败时停止 Controller 发布,不自动重试结果不确定的管理 mutation。恢复后 先确认 Schema 版本、最近 revision、审计和 outbox 一致,再开放 Admin 写入口。
回滚只能回到仍兼容当前 Schema 和 Snapshot 版本的镜像。涉及不可逆数据迁移时, 必须使用前向修复。
4. 容量规划
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. 日常检查
每班次检查:
- Gateway QPS、错误率、p95/p99 和活跃连接。
- Snapshot age、epoch/version、重同步与 ACK 延迟。
- Available Slots、Reserved、Active、各 Proxy 状态数量。
- Provider Success、Empty、Duplicate-only、Error、429 与退避。
- Checker 队列、SUSPECT 数、检查延迟和目标级失败。
- Extract requested/returned、insufficient、冲突和幂等命中。
- PostgreSQL 连接、管理事务失败、outbox backlog、WAL 与备份。
- Redis 延迟、内存、TTL 淘汰、原子操作错误、主从状态和 Leader 租约抖动。
Prometheus 标签禁止包含 Proxy IP、Client ID、Session、完整 URL、request ID。 需要逐请求调查时使用受控、脱敏且采样的结构化日志。
6. 优雅停机
Gateway
- readiness 立即失败,停止新连接。
- 停止应用新 Snapshot,但保留当前不可变版本。
- 等待 HTTP 请求和 CONNECT 隧道排空。
- 到达 60 秒上限后关闭残余连接,保证容量 reservation 被释放。
Controller
- 停止接收新的 Extract/Admin 写请求。
- 停止发起 Fetch,释放 Provider Leader 租约。
- 等待已提交 Redis 原子操作返回;未确认请求的客户端必须使用相同幂等键重试。
- 刷新 Admin outbox、审计和 Worker ACK,再关闭 PostgreSQL/Redis 连接池。
Outbox 发布器必须以稳定 consumer ID 有界领取;发布成功后原子 ACK。进程在发布 成功但 ACK 结果不确定时,不得伪造确认;等待租约到期后重领,并由下游事件消费者 按事件 ID/revision 去重。持续积压时先暂停新的管理变更,检查发布目标、租约和 最老未发布事件,不删除未发布行。
Checker
- 停止领取新任务。
- 在 45 秒内完成或取消现有探测。
- 批量上报已完成 Observation,未完成任务由队列重新投递。
7. 故障处置
7.1 Snapshot 陈旧
症状:ProxyPoolGatewaySnapshotStale、Worker 重同步增加、Gateway Ready 下降。
- 检查 Controller、控制流和 outbox 延迟。
- 确认 Worker epoch 与 Controller epoch,禁止手工降低 epoch。
- 缺版本时强制完整 Snapshot,不要继续应用 Delta。
maxStaleAge内允许旧 Snapshot 服务;超限自动拒绝新流量并排空。- 不得通过无限增大
maxStaleAge隐藏控制面故障。
7.2 PostgreSQL 不可用
- Gateway 继续使用最后有效 Snapshot。
- Redis 健康且运行配置有效时,Distribution 继续执行原子 Extract,Provider 继续刷新 TTL 活动池。
- 拒绝配置版本、Upstream/Routing 管理状态和其他需要 Admin 审计/outbox 的写入; 不得把 Proxy 明细临时落入 PostgreSQL。
- 恢复后核对迁移、管理事务回滚、Admin 审计与 outbox backlog;不存在 Proxy 明细或逐次提取记录恢复步骤。
7.3 Redis 不可用
- Gateway 继续读取节点内最后有效 Snapshot,直到
maxStaleAge;请求热路径不 回查 PostgreSQL 或 Provider。 - Distribution 立即失败关闭并返回 503,禁止本地内存提取或 PostgreSQL 兜底。
- Controller 停止活动池写入和需要分布式互斥的工作,防止多个 Fetch Leader; 本地限流不能声称满足全局额度。
- 恢复后确认 Leader 唯一和租约 epoch 单调,由 Provider 重新 Fetch 并构建 TTL 活动池,再恢复 Distribution。Redis 整体丢失会终止原活动池代次的排他状态和 短期幂等窗口;高可用、持久化、监控和告警必须明确并降低该风险。
7.4 Provider 故障
- 超时、DNS、认证、非预期 HTTP、响应超限与模板错误全部计 Error。
- 429 尊重
Retry-After,其余 Error 使用指数退避和 jitter。 - Error 不增加 Empty;合法候选为零才增加 Empty。
- Duplicate-only 重置 Empty 并记录独立指标。
- 达到 Empty 阈值后每条受影响 Routing 只原子切换一次。
7.5 Gateway 容量耗尽
- 检查 Available Slots,而不是只看 Proxy 数量。
- 确认是否大量容量停留在 Reserved,排查 Commit/Cancel 泄漏。
- 检查 TTL safety margin、健康状态和 Worker 所有权是否导致候选被过滤。
- 快速拒绝新请求,禁止无界等待或把压力转移到 Controller。
- 扩容 Gateway 前确认存在可分配 Proxy 所有权切片。
7.6 Extract 库存不足
partial返回实际数量;allOrNothing不足时不改变 Redis 活动池。- 检查 TTL、health age、filter、Worker ownership 和
reserveForGateway。 - 不得降低
reserveForGateway到导致 Gateway 容量告警的水平。 - 回收 Worker-owned Proxy 必须先 DRAINING、等待 active/reserved 为零、清除 ownership,再由 Redis 原子操作将其从可分配活动池移除并写入短期幂等结果。
- 已提取代理没有 Release;客户端归还请求只记录为无效调用,不恢复库存。
7.7 Checker 积压
- 优先新 Proxy 与 SUSPECT 复检。
- 降低稳定 AVAILABLE 的普通复检频率。
- 检查目标超时、DNS 与出口网络,再按任务延迟扩容 Checker。
- 队列必须有上限;不得无限积压耗尽内存或 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 轮换
- 创建新 Secret 版本,不覆盖旧值。
- Provider/API 凭据支持双版本重叠时先发布新版本。
- 更新配置 Revision,确认 Controller 成功重建 Adapter。
- 观察 Fetch Error、认证失败与 Snapshot ACK。
- 所有副本应用后撤销旧 Secret。
Proxy 凭据轮换必须增加 credentialVersion,确保唯一键不会把新旧凭据错误合并。