# Proxy Pool
## 项目定位
面向多供应商动态代理资源的集中控制、独占提取与高并发转发平台。
Proxy Pool 将供应商接入、短 TTL 代理活动池和管理状态集中到 Controller,
同时提供三类边界清晰的访问方式。集群 `100,000 QPS` 是设计目标,尚未经过
代表性环境的负载测试证明。
## 项目背景
不同代理供应商的响应格式、鉴权方式、计费方式和代理存活时间并不一致;部分
代理只有几十秒有效期。系统还需要同时处理容量预留、健康状态、路由切换、
一次性提取和高并发转发。
Proxy Pool 用 Controller 协调这些变化,并让 Gateway 数据面只消费节点内存中的
不可变快照,避免在转发热路径查询 PostgreSQL、Redis 或 Provider API。
## 使用方式
- **Gateway**:调用方连接平台,由平台选择上游代理并转发 HTTP 或 HTTPS
CONNECT。`proxy-gateway` 已装配本地监听、指标探针和控制面 Register/Watch/ACK/
Runtime/Outcome 会话;带凭据 Proxy 的分发与当前内存 View 已闭环。
- **Distribution**:调用方按条件提取真实代理;成功提取即独占消费,不支持归还、
续租或状态查询。
- **Admin**:运维人员查询状态、启停 Upstream、切换 Routing,并触发严格配置
重载。Admin 与 Distribution 已由 Controller 运行在独立监听器上。
## 核心能力
- **严格配置**:配置版本 1、YAML 未知字段拒绝、Secret 引用解析、公开监听保护、
引用和容量边界校验。
- **Provider 获取与协调**:Provider HTTP Client、响应上限、模板解析、分布式
Leader/请求额度、退避和补池 Supervisor 已接入 Controller。
- **Redis 活动池**:短 TTL Proxy Upsert、去重、健康更新、Worker ownership、
库存、过期清理、Distribution 幂等与分布式限流均使用原子操作或有界流程。
- **Distribution**:支持 `partial` / `allOrNothing`、TTL 与健康过滤、Gateway
库存预留,以及 `AVAILABLE -> EXTRACTED` 的一次性独占提取。
- **Controller 入口**:`proxy-controller` 已装配 Distribution、Admin、Metrics、
PostgreSQL 迁移与 Redis 活动池,并支持联动优雅停机。
- **Checker 指标**:Metrics 启用时暴露 Checker 任务下发与 Observation 接受/拒绝计数;
标签仅使用固定检查级别和结果,不记录 Proxy、IP、URL 或凭据。
- **Gateway 指标**:Metrics 启用时暴露代理尝试的固定阶段成功/失败计数、本地
Outcome 队列满后的丢弃计数、HTTP/CONNECT 已接收请求数与在途数,以及活跃
CONNECT 隧道数和请求生命周期 p50/p95/p99 直方图;协议标签仅有 HTTP 与 CONNECT,不记录 Proxy、路由、目标、
客户端或凭据。
- **Drain 指标**:Controller 暴露 `proxy_pool_controller_drain_candidates_total` 与
`proxy_pool_controller_drains_started_total`;`reason` 仅有 `unhealthy` 与
`upstream_disabled`,不包含 Proxy、Worker、Upstream、会话或地址。
- **Provider 指标**:Controller 暴露
`proxy_pool_controller_provider_fetch_results_total{class}`、
`proxy_pool_controller_provider_valid_candidates_total` 与
`proxy_pool_controller_provider_new_proxies_total`;`class` 仅有 `valid`、
`empty`、`duplicate_only`、`error`,不包含 Upstream、Proxy 或错误文本标签。
- **提取指标**:Controller 暴露
`proxy_pool_controller_extraction_requests_total{result}`、
`proxy_pool_controller_extraction_requested_proxies_total` 与
`proxy_pool_controller_extraction_returned_proxies_total`;`result` 仅有完成、
部分、空、库存不足、幂等冲突、限流、不可用、无效与内部错误等固定枚举,
不包含 Client、请求、过滤条件、Upstream、Proxy 或错误文本标签。
- **容量指标**:Controller 在既有 Provider 库存对账周期聚合托管 Proxy、可用/有效
Slot、待拉取数量和活跃上游数,并暴露
`proxy_pool_controller_capacity_inventory_reads_total{result}`;`result` 仅有
`success` 和 `error`,不按 Upstream、Worker、Proxy、会话或地址拆分。
- **PostgreSQL 管理面**:持久化配置版本、Upstream/Routing 管理状态、Admin
审计与 Outbox;不保存 Proxy 明细或逐次提取记录。
- **Gateway 组件**:HTTP 正向代理、HTTPS CONNECT、双向 Tunnel、重试、超时、
目的地址保护、本地快照存储、容量调度和 Worker 控制面 Register/Watch/ACK/
Runtime/Outcome 会话组件已有实现与定向测试。每次代理尝试只向本地有界队列写入
Outcome,微批确认失败会重发同一序列;队列满时丢弃观测样本,不阻塞转发请求。
`SessionSupervisor` 会为可恢复控制面中断执行
有界退避重连。Controller 可向 Worker 下发已归属 Proxy、Gateway Routing 与按引用去重的
凭据材料快照。Gateway 会将 Routing、Proxy 与凭据原子编译为同一内存 View,并只按当前未过期
View 匹配请求,并在内存中按 Sequential、Random、Round Robin、Weighted 或 Least
Connections 选择上游。无候选时支持 reject、受 `waitTimeout` 限制的本地容量等待,
以及仍经过目标地址策略的 direct;`proxy-gateway` 通过独立控制面拨号地址维护
Session,并在每份 Snapshot 有效期的一半前接收版本递增的完整刷新;仅在持有未过期
Snapshot 时 Ready,凭据材料只保留在当前节点内存 View。Controller 内成功提交的
Upstream 启停、Routing 切换和配置发布会向本进程全部在线 Worker 快照流广播刷新;
定时刷新仍作为跨进程收敛与失效保护。
- **Gateway 粘性会话**:可为已认证请求启用 X-Proxy-Session 等配置 Header;
Gateway 以 Client、Routing 和会话值派生本地有界绑定,成功建连后固定到同一
Proxy,并在代理失效、快照移除或转发失败时自动重绑。原始会话值不会写入日志、
指标、PostgreSQL 或 Redis,也不会向目标站点转发。
- **安全边界**:Gateway、Distribution 与 Admin 使用各自的认证语义,并支持
CIDR、可信代理、严格请求解析和敏感信息最小化;Admin 的读写权限与
Distribution 提取权限可按命中凭据分别收敛。Distribution 凭据还可限制单次
提取数量、可访问 Upstream 与地区,Gateway 凭据可限制可访问 Routing;未配置时
保持既有全范围行为。Gateway 凭据还可在每个 Worker 内限制每分钟请求数,
同时限制 HTTP 请求和 CONNECT 隧道的并发数;热路径计数不写入 Redis 或
PostgreSQL。
## 架构概览
```mermaid
flowchart LR
Client[调用方] -->|HTTP / CONNECT| Gateway[proxy-gateway]
Client -->|独占提取| Distribution[Distribution]
Operator[运维人员] -->|管理操作| Admin[Admin]
subgraph CP[proxy-controller 已运行]
Distribution --> Controller[Controller]
Admin --> Controller
end
Controller -->|Fetch| Provider[Provider API]
Controller --> Redis[(Redis)]
Controller --> PostgreSQL[(PostgreSQL)]
Checker[Checker
任务协议已接入] -. Observation .-> Controller
Controller -. gRPC Snapshot .-> Gateway
```
- **PostgreSQL** 只保存管理面状态,不保存 Proxy 明细或逐次提取记录。
- **Redis** 保存短 TTL Proxy 活动池、Provider 协调、Distribution 幂等与分布式
限流等可重建的短期状态。
- **Gateway 热路径** 只读取节点内存,不查询 PostgreSQL、Redis 或 Provider API。
## 当前完成度
截至 **2026-08-07**,实施计划中可直接勾选的检查项为 **71 / 75(94.7%)**。详情见
[实施计划](docs/development/implementation-plan.md)和
[交付完成度审计](docs/requirements/completion-audit.md)。
- **已完成**:严格配置、Provider 获取与协调、Redis 活动池、Distribution 原子
提取与限流、Controller 的 Admin/Distribution/Metrics 监听,以及 PostgreSQL
管理状态与有界审计查询;WorkerControlPlane 的 Register、Snapshot ACK、Runtime 心跳接收和
Redis 会话栅栏,以及 Gateway Outcome 上报的有界队列、序列确认与重试;
Controller 的 Redis 共享 BASIC/EGRESS/TARGET 检查任务、按上游的有界轮转调度、HTTP/HTTPS/SOCKS5
Checker 探测和
Observation 状态归并;Provider 连续空结果与管理态禁用当前项触发的 Sequential CAS
自动推进、禁用候选过滤、末端路由停用和 Snapshot 即时刷新。
- **部分完成**:Kubernetes 运行时 mTLS Overlay;Compose 已具备本地的
Controller/Gateway/Checker mTLS 运行链路。
- **待完成**:故障演练和代表性集群压测;现有 HTTP、CONNECT 长连接和 Extract
场景只提供可复现的负载工具,不构成容量验证结论。
检查项数量不等于生产就绪度。CI 会验证 OpenAPI 契约、固定版本的 protobuf descriptor/
生成代码漂移,以及 Compose/Kustomize 的静态渲染;这些门禁也不代表
端到端拓扑已经完成;`100,000 QPS` 仍只是待验证的集群设计目标。
## 快速开始
前置条件为 Go 1.26、PowerShell,以及用于 fixture 测试的 Docker。先在当前
PowerShell 会话设置本地占位凭据;这些值仅用于本地验证:
```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 = "LOCAL_PROVIDER_A_TOKEN"
$env:PROVIDER_B_TOKEN = "LOCAL_PROVIDER_B_TOKEN"
$env:PROXY_POOL_CONFIG_FINGERPRINT_KEY = "LOCAL_HIGH_ENTROPY_KEY_AT_LEAST_32_BYTES"
```
`PROXY_POOL_CONFIG_FINGERPRINT_KEY` 在 Admin 启用时必须至少为 32 字节,并与业务
Secret 分离管理。
校验配置并执行仓库验证:
```powershell
go run ./deploy/tools/configcheck deploy/config/local.yaml
./scripts/verify.ps1
./scripts/package-docs.ps1
./scripts/benchmark-gateway.ps1
```
`package-docs.ps1` 默认生成被忽略的 `dist/proxy-pool-docs-v1.0.zip`;包内包含 README、
`docs/`、图表、OpenAPI、Proto 契约和部署手册,并以 `manifest.json` 记录 Git revision、文件大小和
SHA-256。可使用 `-Version vMAJOR.MINOR[.PATCH]` 与 `-OutputPath OUTPUT.zip` 生成指定交付物。
`benchmark-gateway.ps1` 固定执行一次 100k 索引调度、Routing Round Robin 和 Snapshot Apply
微基准,并把版本与原始输出写入 `dist/gateway-benchmarks.txt`;它用于回归比较,不构成
网络转发或 100k QPS 集群容量证明。
Redis、PostgreSQL 和 Controller fixture 脚本会使用 Docker 启动隔离依赖:
```powershell
./scripts/test-redis.ps1
./scripts/test-postgres.ps1
./scripts/test-controller.ps1
```
本地 Compose 还会启动 Controller、两个固定身份的 Gateway 和一个 Checker。首次启动前
生成仅用于本机的 7 天 mTLS 证书;输出目录受 `.gitignore` 保护,脚本拒绝写入非空目录:
```powershell
./scripts/generate-local-controlplane-certs.ps1
docker compose -f deploy/docker-compose.yml up -d --build
docker compose -f deploy/docker-compose.yml ps
```
Gateway 只有取得有效 Snapshot 后才会通过 `/readyz`;Checker 在首次成功领取控制面任务
批次后才会通过 `/readyz`,空批次也代表连接和身份验证已经成功。后续任务领取失败会立即
撤销 Checker 的就绪状态。
PostgreSQL 与 Redis 是 Controller 的启动依赖。当前可运行的 Controller 入口如下,
将 `CONFIG_FILE` 替换为实际配置路径,并确保其中的 PostgreSQL 与 Redis 地址可从
进程所在网络访问:
```powershell
go run ./cmd/proxy-controller -config CONFIG_FILE
```
[`deploy/config/local.yaml`](deploy/config/local.yaml) 面向 Compose 网络,默认使用
服务名 `postgres` 和 `redis`;它可直接用于配置校验,但宿主机执行 `go run` 时需要
改用宿主机可达的存储地址。
本地配置中的 `.invalid` Provider URL 是故障演示占位,不会提供真实代理。
Gateway 也可独立启动;需要启用 Controller `controlPlane` 并配置匹配的 mTLS
证书(回环 fixture 可使用明文),再提供独立的拨号地址和 Worker 身份:
```powershell
go run ./cmd/proxy-gateway -config CONFIG_FILE `
-control-plane CONTROLLER_HOST:8443 `
-cluster-id CLUSTER_ID -worker-id WORKER_ID `
-instance-id INSTANCE_ID -zone ZONE
```
以上参数也可通过 `PROXY_POOL_CONTROL_PLANE_ADDRESS`、`PROXY_POOL_CLUSTER_ID`、
`PROXY_POOL_WORKER_ID`、`PROXY_POOL_INSTANCE_ID` 与 `PROXY_POOL_ZONE` 提供。
生产工作负载可设置 `PROXY_POOL_AUTO_IDENTITY=true`,省略 Worker 和 Instance ID;
Gateway 会从挂载的 `gatewayTLS` 证书解析
`spiffe:////worker/`,并将 ``
作为默认实例身份。Controller 仍会将请求 ID 与证书 URI 严格比对。
Gateway 的 `/livez`、`/readyz`、`/metrics` 使用配置中的 `metrics.listen`;无有效
Snapshot 时 `/readyz` 返回 `503`。Checker 使用独立的逻辑/实例身份拉取有界任务:
```powershell
go run ./cmd/proxy-checker -config CONFIG_FILE `
-control-plane CONTROLLER_HOST:8443 `
-checker-id CHECKER_ID -instance-id INSTANCE_ID `
-max-in-flight 64
```
Checker 的参数也可通过 `PROXY_POOL_CONTROL_PLANE_ADDRESS`、
`PROXY_POOL_CHECKER_ID`、`PROXY_POOL_CHECKER_INSTANCE_ID` 与
`PROXY_POOL_CHECKER_MAX_IN_FLIGHT` 提供。`PROXY_POOL_AUTO_IDENTITY=true` 会从
`checkerTLS` 的 `.../checker/` URI 自动派生 Checker 与缺省实例身份。
它不会访问 Redis/PostgreSQL;生产
Controller 在启用控制面时装配 Redis 共享任务 broker,并按启用的 Upstream 调度
HTTP/HTTPS/SOCKS5 BASIC 检查、按每个 `check.urls` 创建 EGRESS 任务,并按启用 Routing 的
`check.targets` 创建 TARGET 任务。调度监督器每轮读取已发布配置;启用 Admin 时只调度配置与
PostgreSQL 管理态同 revision 且均启用的 Upstream 和 Routing。管理态停用 Upstream 会在下一轮阻止新的
BASIC、EGRESS、TARGET 任务;管理态停用 Routing 则停止该 Routing 的新 TARGET 任务。revision 不一致或
状态不完整时按失败关闭。因此 reload 后的上游/路由启停、检查间隔、
抖动、超时、重试次数、`maxInFlight`、EGRESS URL 和 TARGET Profile 都会在下一轮生效;BASIC、
EGRESS 与 TARGET 以有界轮转组共享上游并发上限。新启用的上游无需重启 Controller。
EGRESS 对成功响应提取纯文本 IP 或常见 JSON IP 字段,并将其作为全局健康事实回传;TARGET 事实
仅归并到对应的 `(routing_name, target_url)` Profile,不改变 Proxy 全局健康。
`proxy-loadgen` 的 HTTP 场景可按固定请求数或固定时长运行,并将 HTTPS 目标经
Gateway 的请求交给标准 HTTP Transport 建立 CONNECT:
```powershell
go run ./cmd/proxy-loadgen `
-target https://TARGET_URL/health `
-proxy http://GATEWAY_HOST:8080 `
-requests 10000 -concurrency 128 -timeout 10s
```
CONNECT 长连接场景直接向 HTTP Gateway 发起隧道握手,并在成功后保持每条隧道指定
时长;`-timeout` 只限制 TCP 连接与 CONNECT 响应,`-hold` 控制建连后的保持时间:
```powershell
go run ./cmd/proxy-loadgen `
-scenario connect -target https://TARGET_URL/ `
-proxy http://GATEWAY_HOST:8080 `
-requests 1000 -concurrency 128 -timeout 5s -hold 30s
```
使用 `-duration 30s -rate 5000` 可运行限速场景;省略 `-rate` 时固定数量 worker
会饱和发送。普通 HTTP 场景中,`-method`、重复的 `-header` 与 `-body` 可组合用于
Distribution 的提取接口:
```powershell
go run ./cmd/proxy-loadgen `
-target http://CONTROLLER_HOST:8081/api/v1/proxies/extract `
-method POST -header "Content-Type: application/json" `
-header "X-API-Key: DISTRIBUTION_API_KEY" -body '{"count":1}' `
-requests 1000 -concurrency 32 -timeout 10s
```
`extract` 场景则自动构造 POST 请求、每请求独立的 `X-Request-ID` 与
`Idempotency-Key`,并只校验响应的 `requestId`、数量和同响应内代理 ID 唯一性:
```powershell
go run ./cmd/proxy-loadgen `
-scenario extract `
-target http://CONTROLLER_HOST:8081/api/v1/proxies/extract `
-header "X-API-Key: DISTRIBUTION_API_KEY" `
-requests 1000 -concurrency 32 -timeout 10s `
-extract-count 1 -extract-fulfillment partial
```
命令输出 JSON 报告,包含成功/失败分类、`TunnelsEstablished`、
`ExtractResponsesValidated`、`ExtractReturned`、`ExtractValidationFailures`、`RateStartsGenerated`、
`RateStartsDropped`、固定内存的
连接握手延迟分位上界、吞吐和 Go 运行时内存/GC 快照。它不会输出提取响应中的地址或
凭据,也不构成 100,000 QPS 证明。限速场景以 `Requests` 表示实际发起数;当
`RateStartsDropped` 非零时,目标速率受压测端并发容量或时间窗限制,报告吞吐不得
标注为已达到配置的 `-rate`。每个生成的限速令牌均会计入实际发起或丢弃,因此
`RateStartsGenerated = Requests + RateStartsDropped`。
需要保留单次容量证据时,使用 `-output REPORT_FILE` 同时写出 JSON 文件;文件在
同目录完整写入后才替换目标,标准输出仍保留相同报告,便于交给日志或指标系统。
`-max-error-rate` 接受 `0` 到 `1`,`-max-p99` 接受正的 Go duration;任一阈值违反时,
报告会附带 `acceptance` 结果,命令仍写出标准输出和 `-output` 文件,然后以退出码 `3`
结束,适合在 CI 中保留失败压测证据:
```powershell
go run ./cmd/proxy-loadgen `
-target https://TARGET_URL/health `
-proxy http://GATEWAY_HOST:8080 `
-duration 30s -rate 5000 -concurrency 128 `
-max-error-rate 0.01 -max-p99 500ms `
-output REPORT_FILE
```
## 关键配置与入口
- [本地配置](deploy/config/local.yaml)与
[完整配置参考](docs/configuration/reference.md)
- [Distribution API](docs/api/distribution.md):默认本地入口
`http://127.0.0.1:8081`
- [Admin API](docs/api/admin.md):默认本地入口 `http://127.0.0.1:8082`
- Controller Metrics:默认本地入口 `http://127.0.0.1:9090`,提供 `/livez`、
`/readyz` 和 `/metrics`
- [控制面协议](docs/api/control-plane.md):Worker/Checker 的 protobuf 契约与
已验证的有界任务领取/Observation 上报边界
- [运维手册](docs/operations/runbook.md):依赖、探针、发布边界与故障处置
## 核心不变量
1. Gateway 热路径只读节点内存,不访问 PostgreSQL、Redis 或 Provider API。
2. Proxy 容量使用 `Reserved -> Active` 原子转换,禁止超卖。
3. Distribution 成功时原子执行 `AVAILABLE -> EXTRACTED`;提取后不归还、不续租。
4. `pool.maxSize` 是当前未提取库存硬上限;`fetch.maxTotal` 是 Redis generation
内的累计获取停止阈值。
5. CONNECT 向客户端提交 `200` 后不透明重放。
6. 公开监听必须有认证或 CIDR 访问保护。
7. PostgreSQL 只保存管理面状态;Proxy 明细只存在于 Redis 短 TTL 活动池和节点
内存,Redis 中的短期状态可由 Provider 重建。
## 路线图
- **P0 - Worker 控制面闭环**:Worker session、Snapshot ledger、ACK、运行态接收、
ownership 索引,以及 Gateway 快照客户端。
- **P0 - Checker 健康链**:BASIC/EGRESS/TARGET 的共享调度、实际探测、Observation reducer 和
`FETCHED -> AVAILABLE / SUSPECT / UNHEALTHY` 状态链已完成;可配置的持续 UNHEALTHY
回收会自动为已分配项发起带健康/归属栅栏的 Drain,待 Snapshot ACK 与运行态归零后再删除;
TARGET 事实按路由目标 Profile 独立归并。
- **P1 - Gateway 与 Routing**:Gateway 进程、快照凭据分发、五种 Routing 策略与
`onUnavailable` 已接入;上游停用会从后续完整 Snapshot 排除,并对现有 Worker
ownership 发起带策略 revision 栅栏的 Drain。Routing 切换立即刷新在线 Worker 的
完整快照;Sequential 的新分配切到新上游,旧 Proxy 与既有连接自然排空。动态容量
调整仍待完成。
- **P1 - 可观测与部署**:低基数业务指标、完整 Compose/Kubernetes 进程拓扑,
以及故障转移和恢复演练。
- **P2 - 容量证明**:`proxy-loadgen`、HTTP/CONNECT/Extract 分场景压测,以及
可复现的代表性 `100,000 QPS` 集群报告。
## 文档导航
**设计与需求**
- [产品设计](docs/design/product-design.md)
- [总体架构](docs/design/architecture.md)
- [项目结构](docs/design/project-structure.md)
- [需求追踪](docs/requirements/traceability.md)
- [架构决策记录](docs/adr/README.md)
**开发与 API**
- [开发指南](docs/development/guide.md)
- [实施计划](docs/development/implementation-plan.md)
- [配置参考](docs/configuration/reference.md)
- [Distribution API](docs/api/distribution.md)
- [Admin API](docs/api/admin.md)
- [控制面协议](docs/api/control-plane.md)
**部署与运维**
- [本地配置](deploy/config/local.yaml)
- [运维手册](docs/operations/runbook.md)
- [生产就绪检查](docs/operations/production-readiness.md)
- [安全模型](docs/security/security-model.md)
**审计与测试**
- [交付完成度审计](docs/requirements/completion-audit.md)
- [测试策略](docs/testing/strategy.md)
- [详细测试策略](docs/testing/test-strategy.md)
- [故障注入](docs/testing/failure-injection.md)