proxy-pool/docs/api/control-plane.md

123 lines
5.4 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.

# Control Plane gRPC API
## 1. 契约范围
Proto 源文件位于 `api/proto/controlplane/v1/controlplane.proto`,包含两项
内部服务:
- `WorkerControlPlane`Worker 注册、Snapshot/Delta 分发、ACK、运行态与结果
批量上报。
- `CheckerControlPlane`:健康检查任务流和 Observation 批量上报。
该协议不承载 Client 的独占提取,也没有 extraction lease/release。Proxy 的
`AVAILABLE -> EXTRACTED` 只在 Controller 调用的 Redis 原子操作中完成。
## 2. Worker 会话
```mermaid
sequenceDiagram
participant W as Gateway Worker
participant C as Controller
W->>C: RegisterWorker(worker, instance, zone)
C-->>W: session + ownershipEpoch + maxStaleAge
W->>C: WatchSnapshots(lastVersion, checksum)
C-->>W: full WorkerSnapshot
W->>W: validate + build immutable snapshot
W->>W: atomic swap
W->>C: AcknowledgeSnapshot(version, epoch, checksum)
loop bounded interval
W->>C: ReportRuntime(active, reserved, draining)
W->>C: ReportOutcomes(batch sequence)
end
```
`worker_id` 是逻辑节点,`instance_id` 区分进程重启,`session_id` 防止旧进程
继续上报。所有权 `epoch` 小于 Controller 当前值的数据必须拒绝。
`ReportRuntimeRequest.report_sequence` 在当前 `session_id` 内严格单调递增。
相同序号只允许内容完全相同的幂等重放;较小序号或相同序号的不同内容必须
拒绝。`observed_at` 只用于观测,不作为乱序判定依据,运行态 TTL 统一使用
Controller 侧 Redis 服务端时间。session 同时保存 Controller 已接受的
`snapshot_version/ownership_epoch`;运行态报告必须与该 ACK 上界完全一致,
Worker 自报的超前版本或 epoch 也必须拒绝。
运行态上报是完整稀疏替换:只携带 Active/Reserved 非零的 Proxy空列表表示
当前会话全部归零。Controller 只有在 Worker session、报告 TTL、Proxy ownership
和 ownership epoch 同时有效时才使用计数;报告缺失、过期或不一致时按零可用
容量 fail-closed不能把未知计数解释成空闲容量。
## 3. Snapshot 与 Delta
完整 Snapshot 包含:
- 单调 `version`、`ownership_epoch`、生成时间和有效期。
- 对该 Worker 可见的有序 Routing。
- 仅归该 Worker 所有的 Proxy、每个 Proxy 的容量、硬过期时间 `expires_at`
和停止新分配的 `usable_until`
- 内容 `checksum`
`usable_until = expires_at - allocationSafetyMargin`。Worker 必须以
`usable_until` 作为最后可分配时刻;达到该时间后即使尚未到 `expires_at`
也不得再为新请求选择该 Proxy。
Delta 声明 `base_version`。Worker 只有在本地版本恰好等于 base 且 checksum
验证成功时才能应用;否则丢弃 Delta 并请求完整 Snapshot。构建在后台完成
热路径只读取一次原子指针。
超过 `max_stale_age` 仍未取得有效快照时Worker 停止接收新流量并排空已有
请求。控制面中断不能让 Worker 查询 PostgreSQL 或 Redis 补偿热路径。
## 4. 所有权与 Drain
同一 Proxy 同时只归一个 Worker。Controller 回收用于独占提取的 Proxy 时:
1. 新 Snapshot 标记或移除该 Proxy使 Worker 停止新预留。
2. Worker 上报 `draining=true` 以及 Active/Reserved。
3. 两个计数都归零后 Controller 清除所有权。
4. 无所有权 Proxy 才能进入 Distribution 的 Redis 原子提取操作。
Worker 崩溃时必须等待所有权 epoch/有效期失效后再转移避免双主。Proto 中
`ReportRuntimeResponse.revoke_proxy_ids` 是加速 Drain 的控制信号,不绕过
Snapshot 版本和 Redis 中的权威所有权状态。
## 5. Outcome 上报
Outcome 按 Worker 单调 `sequence` 批量上报。Controller 返回已接受的最大序号,
从而支持有限重试和去重。阶段区分:
- `DIAL`:连接 Proxy 地址失败。
- `PROXY_HANDSHAKE`HTTP CONNECT 或 SOCKS 握手失败。
- `RESPONSE_HEADERS`:目标响应头前失败。
- `TUNNEL`:隧道建立后结束或失败。
Outcome 是 Observation不直接让 Worker 修改 Redis 活动池状态,也不创建
PostgreSQL Proxy 明细。异步上报队列必须有界;队列满时丢弃低价值样本并计
指标,不能反压 Gateway 热路径。
## 6. Checker 任务
Checker 注册自身最大并发与支持层级Controller 发送有 deadline 的任务:
- `BASIC`:基础连通和协议握手。
- `EGRESS`:出口身份与匿名性。
- `TARGET`:针对 Routing/目标组的可达性。
Checker 只返回 `HealthObservation`。Controller reducer 按 Proxy、检查层级和
Routing 决定 AVAILABLE、SUSPECT 或 UNHEALTHY并更新 Redis 活动池,避免
多个 Checker 并发写状态。
## 7. 兼容与演进
- Proto 字段号一旦发布不得复用。
- 删除字段使用 `reserved` 保留名称和编号。
- 新枚举值必须让旧接收方按 UNSPECIFIED/拒绝策略处理。
- Worker 注册携带 `supported_protocol_version`,不兼容时注册失败而不是静默
降级。
- Stream 断开后使用带 jitter 的有界指数退避,禁止紧密重连。
## 8. 传输安全
集群环境使用 mTLS证书身份绑定 Worker/Checker 类型和环境。服务端校验
消息中的逻辑 ID 与证书授权一致,设置单消息大小、流持续时间、并发 Stream
和上报批次上限。`secret_ref` 是受控引用,不在 Proto 中传播真实密码。