proxy-pool/docs/api/control-plane.md
youfak 6b6fb54075
Some checks are pending
ci / proto (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
ci / integration (push) Waiting to run
feat: publish initial worker snapshots
2026-07-31 13:22:45 +08:00

6.5 KiB
Raw Blame History

Control Plane gRPC API

1. 契约范围

Proto 源文件位于 api/proto/controlplane/v1/controlplane.proto,包含两项 内部服务:

  • WorkerControlPlaneWorker 注册、Snapshot/Delta 分发、ACK、运行态与结果 批量上报。
  • CheckerControlPlane:健康检查任务流和 Observation 批量上报。

该协议不承载 Client 的独占提取,也没有 extraction lease/release。Proxy 的 AVAILABLE -> EXTRACTED 只在 Controller 调用的 Redis 原子操作中完成。

当前实现状态

Controller 已实现并验证 RegisterWorkerAcknowledgeSnapshotReportRuntime 的一元 RPC。Register 创建带 Redis 服务端 TTL 的 sessionACK 只 接受 Controller 已签发的 (version, ownership_epoch, checksum)Runtime 的空 counters 是完整稀疏替换,也续期 session。负向 ACK 会关闭该 session 的 Runtime 写入栅栏,直到收到新的正向 ACK延迟的旧报告不能重新开启它。

生产配置使用 mTLS并将叶子证书 SPIFFE URI 约束为 spiffe://<trust-domain>/<environment>/worker/<worker-id>;仅经配置校验的回环 监听允许明文 fixture 模式。单消息大小、并发流数和 gRPC keepalive 策略由 controlPlane 配置限定。

WatchSnapshots 已在 Register 后发送与当前 ownership epoch 对应的基础完整快照, Gateway 校验后 ACK 并开始 Runtime 心跳。当前基础快照不包含权威 Proxy 或 Routing 内容流会保持等待后续发布权威快照发布器、增量、Gateway 进程装配、Outcome 与 Checker 闭环尚未实现。ReportOutcomes 仍明确返回 Unimplemented100,000 QPS 仍是未验证的设计目标。

2. Worker 会话

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 包含:

  • 单调 versionownership_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_HANDSHAKEHTTP 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 中传播真实密码。