Skip to content

四通道通讯

Control Plane 与 Server App 之间通过四条独立通道通讯,各自承担不同职责,互不干扰。

                    ┌───────────────────┐
                    │  Control Plane    │
                    │     App           │
                    └──┬──┬──┬──┬───────┘
                       │  │  │  │
         Channel ①─────┘  │  │  └─────Channel ④
         Command(mTLS)    │  │        OCSP(Plain HTTP)
         :9091            │  │        :9092
                          │  │
            Channel ②─────┘  └─────Channel ③
            Event SSE              DB Delta
            :9091                  :9091
                       │  │  │  │
                    ┌──┴──┴──┴──┴───────┐
                    │    Server App     │
                    │    (业务节点)      │
                    └───────────────────┘

Channel ① Command(mTLS HTTP)

方向:Server → CP(Server 主动调用)

传输:mTLS HTTP,默认端口 9091

用途:节点心跳、命令拉取、配置同步、结果上报。

Channel ① 是最核心的数据通道,Server 通过它完成所有与 CP 的结构化数据交互。每个端点职责单一,遵循 RESTful 风格。

端点清单

心跳与注册

POST /cp/v2/nodes/:id/checkin

节点定期上报心跳,携带应用版本快照和运行指标(metrics)。CP 据此判断节点在线状态。

命令拉取

POST /cp/v2/nodes/:id/commands/pull?since=N

增量拉取自 since 序号以来的新命令。命令由管理员通过后台下发(如重载配置、执行诊断等)。

命令结果上报

POST /cp/v2/nodes/:id/commands/:cmd_id/result

按命令 ID 逐个上报执行结果,CP 据此更新命令状态。

配置拉取

POST /cp/v2/nodes/:id/configs/pull

增量拉取新的配置项,包括 server_runtime_settingsapp_policyapp_variablesapp_client_ca_bundleapp_mtls_trust_bundlecp_agent_runtime 以及 cloud_function manifest。

配置确认

POST /cp/v2/nodes/:id/configs/acks

批量确认已成功应用的配置项。CP 采用单事务批量 upsert 处理确认,保证原子性。

配置错误上报

POST /cp/v2/nodes/:id/configs/errors

批量上报配置应用失败的错误信息,便于管理员在后台查看和排查。

云函数拉取

GET /cp/v2/objects/cloud-functions/:name?app_id=

按名称和 app_id 拉取云函数脚本体。节点本地缓存脚本,仅在 manifest 变更时重新拉取。

实现细节

Server 端由 ControlPlaneAgent(后台 strand)负责调度所有 Channel ① 请求。底层通过 co_await asio::post(cp_io) 将 blocking 的 httplib 调用派发到 cp_io_threads 池,完成后自动回到 BackgroundRuntime

Channel ② Event SSE

方向:CP → Server(CP 主动推送)

传输:SSE(Server-Sent Events),共用 mTLS 端口 9091

用途:实时推送事件提示(hint),触发 Server 通过 Channel ① 拉取详细数据。

设计哲学

Event SSE 只传递轻量级提示(hint),不携带业务数据。Server 收到 hint 后通过 Channel ① 按需拉取完整数据。这种设计:

  • 避免 SSE 消息过大
  • 保证数据一致性(拉取是幂等的)
  • SSE 降级时 Server 自动切换到轮询模式

连接端点

GET /cp/v2/nodes/:id/events

事件类型

事件名含义Server 响应动作
command.pending有新命令待执行调用 commands/pull 拉取
config.pending有新配置待应用调用 configs/pull 拉取
blacklist.changed黑名单发生变更触发 Delta Puller 立即拉取
epoch.bumped认证 epoch 已递增触发 Delta Puller 立即拉取

连接管理

  • 每节点一连接:新连接到达时自动踢掉旧连接,避免重复推送
  • Keep-alive:每 30 秒发送 ping 消息维持连接
  • 健康探针:Server 端监控连接状态,用于判断是否降级
  • 队列溢出策略:事件队列满时丢弃最旧的事件(新事件优先)

实现细节

CP 端使用 cp::event::EventBus(进程内 pub/sub)+ httplib chunked content provider 实现 SSE 流。

Server 端由 CpEventSubscriberIBackgroundService 实现)在专用的 sse_pool(固定 1 线程)上运行。SSE 连接通过 blocking httplib::Get 持续数小时甚至数天,独占一个线程。这正是 sse_poolcp_io_threads 物理隔离的原因——避免长连接占用短任务 burst 池的线程。

Channel ③ DB Delta

方向:Server → CP(Server 主动拉取)

传输:复用 Channel ① 的 mTLS HTTP 连接

用途:增量同步安全关键数据(认证 epoch 变更、黑名单变更)。

同步表

表名内容
auth_epoch_changes认证 epoch 变更记录
server_blacklist_changes服务端黑名单变更记录

RuntimeSecurityDeltaPuller

RuntimeSecurityDeltaPuller 持续增量拉取上述变更表,将数据落入本地 Runtime DB 和内存缓存。

自适应拉取间隔

拉取间隔根据 Channel ② 的健康状态动态调整:

Channel ② 状态拉取间隔
健康(SSE 连接正常)5 秒 / 30 秒(不同数据类型)
降级(SSE 连接断开)800 毫秒 / 5000 毫秒

当 SSE 连接健康时,关键变更由 blacklist.changed / epoch.bumped 事件实时触发拉取,定时轮询仅作为兜底。当 SSE 降级时,DeltaPuller 自动缩短轮询间隔以弥补实时性损失。

数据流向

CP Control DB → HTTP Response → DeltaPuller → Runtime DB + 内存缓存

Server 的运行时黑名单以本地 Runtime DB 为单一真相来源,不依赖 CP 下发快照。

Channel ④ OCSP(Plain HTTP)

方向:Server → CP(Server 主动请求)

传输:Plain HTTP(非 TLS),独立端口,默认 9092

用途:为 SDK 客户端提供 OCSP Stapling 所需的证书吊销状态证据。

为什么是 Plain HTTP?

OCSP 协议自身已通过 RSA-SHA256 签名保护响应完整性(RFC 6960),传输层无需再加 TLS 加密。使用 Plain HTTP 有两个优势:

  1. 降低开销:免去 mTLS 握手成本
  2. 端口隔离:独立端口和线程池(ocsp_thread_pool_count),与 Channel ①/② 的 mTLS 连接完全不争用 worker

OCSP 端点

POST /ocsp/

遵循 RFC 6960 标准 OCSP 请求/响应格式。

OcspStaplingManager

Server 端的 OcspStaplingManager 负责周期性获取 OCSP 响应并缓存:

  • 刷新周期:约 15 分钟,根据响应中的 nextUpdate 字段自适应调整(取 nextUpdate / 2
  • 缓存策略:在 nextUpdate 有效期内使用缓存的 OCSP 响应
  • Staple 到握手:将 OCSP 响应附加到 TLS 握手过程,供 SDK 验证

CP 端 OCSP 响应器

CP 的 OcspResponder 对每个请求现场签发 OCSP 响应,不做服务端缓存。签名使用 RSA-SHA256。

吊销处理(Plan C 设计)

当节点证书被吊销时,OCSP 响应会返回 revoked 状态。此时 Server 的行为:

  1. 继续 staple revoked 响应给 SDK——SDK 的 must-staple 验证会拒绝握手,业务面 fail-closed
  2. 不自行关停——管控通道(mTLS /cp/v2/*、SSE、Delta)保持存活
  3. 可恢复——管理员在后台 re-enable 证书后,节点自动恢复正常

这一设计确保了:

  • 被吊销节点的业务立即中断(SDK 拒绝连接)
  • 管控通道保持畅通,便于远程恢复
  • 无需人工到场重启节点

SDK 端验证

SDK 在 TLS 握手阶段使用 ocsp_signer_ca.pem(即 tcp_server_ca 信任锚)验证 OCSP 响应:

  • 验证 OCSP 响应签名
  • 校验时间窗(maxsec=1800s)
  • 检查 cert_status(good / revoked / unknown)
  • must-staple 策略:无 staple 时直接拒绝握手

通道间协作

四条通道协同工作的典型场景:

场景一:配置变更下发

1. Admin 修改应用策略
2. CP 写入 Control DB
3. CP 通过 Channel ② 推送 config.pending 事件
4. Server 收到事件,通过 Channel ① 调用 configs/pull
5. Server 应用配置,通过 Channel ① 调用 configs/acks 确认

场景二:节点证书吊销

1. Admin 在后台吊销节点证书
2. CP 更新证书状态
3. Server 通过 Channel ④ 获取 OCSP 响应(revoked)
4. Server 继续 staple revoked 响应
5. SDK 连接时 must-staple 验证失败,拒绝握手
6. 管控通道(Channel ①②③)保持正常,等待恢复

场景三:SSE 降级兜底

1. Channel ② SSE 连接断开
2. Channel ③ DeltaPuller 自动缩短轮询间隔(800ms/5000ms)
3. 安全关键数据仍能及时同步
4. SSE 重连后自动恢复正常间隔

下一步