architecture.md - 文档

GatewayWorker-Go 架构原理

整体架构

GatewayWorker-Go 采用 Gateway + Worker 分离 的架构,将网络 IO 与业务逻辑解耦,实现高性能、可横向扩展的实时通讯服务。

                         ┌──────────────────┐
                         │     Register     │
                         │    (注册中心)     │
                         └─┬──────┬──────┬──┘
                  注册/发现│      │      │发现Gateway地址
             ┌────────────┘      │      └────────────────┐
             ▼                   │注册/发现               ▼
┌────────────────────────┐       │        ┌──────────────────────┐
│        Gateway         │       │        │     GatewaySDK       │
│  (网关,管理客户端连接)  │       │        │    (独立推送 SDK)     │
└──┬──────────────────┬──┘       │        └──────────┬───────────┘
   │                  │          │                   │
   │ WebSocket/TCP    │ GatewayProtocol+AES          │ GatewayProtocol+AES
   │ (对外客户端)     │ (内部命令端口)                │ (连接内部命令端口)
   ▼                  ▼          ▼                   │
┌────────┐    ┌──────────────────────┐               │
│ Client │    │    BusinessWorker    │◄──────────────┘
│        │    │    (业务逻辑处理)     │  (走同一个内部端口,
└────────┘    └──────────────────────┘   认证方式不同)

GatewaySDK 本质上是一个"主动型 BusinessWorker":它和 BusinessWorker 一样连接 Register 发现 Gateway 地址,然后连接 Gateway 的内部命令端口发送指令。区别在于:

  • BusinessWorker 使用 CMD_WORKER_CONNECT 认证,被动接收 Gateway 转发的客户端事件
  • GatewaySDK 使用 CMD_GATEWAY_CLIENT_CONNECT 认证,主动向 Gateway 发送推送/查询等指令

工作流程

  1. 启动 Register — 监听 TCP 端口,等待 Gateway 和 Worker 注册
  2. 启动 Gateway — 向 Register 注册自己的内部通讯地址,同时监听客户端连接(WebSocket/TCP)
  3. 启动 Worker — 向 Register 注册,Register 回复所有 Gateway 地址,Worker 连接所有 Gateway
  4. 客户端连接 — 客户端通过 WebSocket 或 TCP 连接到 Gateway
  5. 消息转发 — Gateway 收到客户端消息后,通过内部协议转发给 Worker
  6. 业务处理 — Worker 执行业务逻辑(用户编写的回调函数),通过 API 向客户端发送响应

消息流转详细过程

客户端发送消息:
  Client --[WebSocket/TCP]--> Gateway --[GatewayProtocol+AES]--> Worker
                                                                  │
                                                           OnMessage(clientID, msg)
                                                                  │
                                                        gateway_api.SendToClient()
                                                                  │
  Client <--[WebSocket/TCP]-- Gateway <--[GatewayProtocol+AES]----┘

为什么分离 Gateway 和 Worker?

优势 说明
热更新 重启 Worker 不影响客户端连接,Gateway 维持长连接
横向扩展 Gateway 和 Worker 可独立扩容,按需分配资源
职责分离 Gateway 专注 IO,Worker 专注业务,互不干扰
分布式部署 三个组件可部署在不同服务器上

五个组件详解

Register(注册中心)

支持的事件

事件 发送方 说明
gateway_connect Gateway Gateway 注册,携带内部通讯地址
worker_connect Worker Worker 注册,携带 worker 名称
worker_stats Worker Worker 每 3 秒上报处理计数
admin_connect Dashboard 管理后台连接,订阅实时状态推送
ping 任意 心跳保活
broadcast_addresses Register 广播 Gateway 地址列表给 Worker
status_update Register 推送完整状态(gateways+workers)给 Admin

多 Register 高可用原理

Register-A (192.168.1.10:51234)     Register-B (192.168.1.11:51234)
     ▲    ▲                              ▲    ▲
     │    └──── Worker ──────────────────┘    │
     │                                        │
     └──────── Gateway ──────────────────────┘

• 每个 Gateway 向所有 Register 注册(独立连接)
• 每个 Worker  连接所有 Register 接收广播
• Register 之间互不通信,各自独立维护地址列表
• 任一 Register 宕机,其余 Register 继续提供服务发现
• 所有 Register 都宕机时,已建立的 Gateway⇔Worker 连接不受影响

Gateway(网关)

Gateway 维护两类连接:

对外连接(客户端)

对内连接(Worker/GatewaySDK)

路由策略

BusinessWorker(业务处理器)

GatewaySDK(独立推送 SDK)

Dashboard(监控面板)


通讯协议

客户端协议

WebSocket:标准 WebSocket 协议,消息直接作为帧收发。

TCP:4 字节长度前缀协议:

┌────────────────────┬──────────────────────┐
│ 4字节 pack_len (BE)│  pack_len 字节 body  │
└────────────────────┴──────────────────────┘

GatewayProtocol(内部二进制协议)

Gateway 与 Worker 间的通讯协议,28 字节固定头部 + 变长数据,全部 Big-Endian:

偏移  大小  字段            说明
─────────────────────────────────────
 0    4    pack_len        整包长度
 4    1    cmd             命令字
 5    4    local_ip        Gateway 内网 IP
 9    2    local_port      Gateway 内部端口
11    4    client_ip       客户端 IP
15    2    client_port     客户端端口
17    4    connection_id   连接 ID
21    1    flag            标志位
22    2    gateway_port    Gateway 对外端口
24    4    ext_len         ext_data 长度
28    变长  ext_data        扩展数据 (session等)
28+N  变长  body            包体

命令字一览

命令 方向 说明
CMD_ON_CONNECT 1 G→W 新客户端连接
CMD_ON_MESSAGE 3 G→W 客户端消息
CMD_ON_CLOSE 4 G→W 客户端断开
CMD_SEND_TO_ONE 5 W→G 发给单个客户端
CMD_SEND_TO_ALL 6 W→G 广播
CMD_KICK 7 W→G 踢出客户端
CMD_DESTROY 8 W→G 销毁连接
CMD_UPDATE_SESSION 9 W→G 合并 session
CMD_BIND_UID 12 W→G 绑定 UID
CMD_UNBIND_UID 13 W→G 解绑 UID
CMD_SEND_TO_UID 14 W→G 向 UID 发送
CMD_JOIN_GROUP 20 W→G 加入分组
CMD_LEAVE_GROUP 21 W→G 离开分组
CMD_SEND_TO_GROUP 22 W→G 向分组发送
CMD_UNGROUP 27 W→G 解散分组
CMD_WORKER_CONNECT 200 W→G Worker 认证
CMD_PING 201 双向 心跳
CMD_GATEWAY_CLIENT_CONNECT 202 C→G GatewaySDK 认证
CMD_ON_WEBSOCKET_CONNECT 205 G→W WS 握手完成

Client ID 编码

每个客户端有一个全局唯一的 20 字符 hex 标识符(client_id),编码规则:

client_id = hex( uint32(local_ip) + uint16(local_port) + uint32(connection_id) )
            ──── 4字节 ────────── ─── 2字节 ──────────── ──── 4字节 ────────────
            = 10字节二进制 → 20字符十六进制

通过 client_id 可以直接解码出所在 Gateway 的地址,实现精确寻址。


安全机制

所有内部通讯均使用 AES-256-CBC 加密 + SecretKey 认证双重保护:

密钥派生

AES Key = SHA256(SecretKey) → 32 字节

Register 通讯加密

发送: JSON → AES-256-CBC加密(随机IV) → Base64编码 → 追加\n → TCP发送
接收: 按\n分隔 → Base64解码 → AES-256-CBC解密 → JSON解析

Gateway⇔Worker 通讯加密

发送: GatewayProtocol.Encode() → AES-256-CBC加密 → 前置4字节(密文长度) → TCP发送
接收: 读4字节长度 → 读密文 → AES-256-CBC解密 → GatewayProtocol.Decode()

认证流程

Gateway → Register:  {"event":"gateway_connect", "secret_key":"xxx", "address":"ip:port"}
Worker  → Register:  {"event":"worker_connect", "secret_key":"xxx", "name":"worker:0"}
Admin   → Register:  {"event":"admin_connect", "secret_key":"xxx"}
Worker  → Register:  {"event":"worker_stats", "name":"worker:0", "processed_count":12345}
Worker  → Gateway:   CMD_WORKER_CONNECT, body={"worker_key":"name:id", "secret_key":"xxx"}
Client  → Gateway:   CMD_GATEWAY_CLIENT_CONNECT, body={"secret_key":"xxx"}

Register 和 Gateway 均会验证 secret_key,不匹配则立即断开连接。