Files
Edu/docs/modules/push-gateway/README.md

11 KiB
Raw Blame History

push-gateway 推送网关服务

版本1.0(仲裁回写) 日期2026-07-10 状态P5 已交付 关联文档:


1. 模块职责

push-gateway 是实时推送基础设施服务Go 实现),管理 WebSocket 长连接(仅 WebSocket不支持 SSE — ISSUE-001。 接收 msg 服务的推送请求HTTP /internal/* + Kafka 事件),维护用户在线连接池,将消息实时投递到浏览器/移动端。 支持连接鉴权JWT RS256、RFC 6455 控制帧心跳、断线重连、多设备同步、连接数监控、跨实例 Pub/Sub 广播。

无 DBISSUE-005消息审计、离线落库、重试队列均由 msg 服务负责。


2. 技术栈

类别 技术 版本 用途
语言 Go 1.25+ 高并发长连接
Web 框架 Gin 1.12+ HTTP 升级 WebSocket + 内部 API
WebSocket gorilla/websocket 1.5+ WebSocket 协议
缓存 Redis 7.x 在线连接表、pub/sub 跨实例 fanout
Kafka segmentio/kafka-go 0.4+ 消费 edu.notification.requested(纯 Go无 cgo
JWT golang-jwt/jwt/v5 5.2+ RS256 token 校验via shared-go/jwks
配置 shared-go/env 环境变量加载(替代 viper
日志 log/slog stdlib 结构化日志JSON prod / text dev
追踪 OpenTelemetry 1.44+ 分布式追踪via shared-go/tracer
指标 prometheus/client_golang 1.23+ Prometheus 指标
共享包 shared-go tracer/logger/env/jwks 复用ARB-015 §17.5
编排 Kubernetes 1.28+ 生产部署

3. 架构图

graph TB
    MSG[msg 服务] -->|HTTP /internal/push| PG[push-gateway]
    MSG -->|Kafka edu.notification.requested| PG
    PG --> HUB[Hub<br/>连接池管理<br/>map userID -> connID -> Connection]
    HUB --> C1[用户 1 连接]
    HUB --> C2[用户 2 连接]
    HUB --> CN[用户 N 连接]
    PG --> REDIS[(Redis<br/>在线 SET + pub/sub)]
    MFE[微前端] -.WebSocket /ws?token=JWT.-> PG
    PG --> HEART[心跳保活<br/>RFC 6455 Ping/Pong 30s]
    PG --> JWKS[iam JWKS<br/>RS256 公钥 5min 缓存]
    PG --> METRICS[/metrics<br/>9 个 Prometheus 指标]

完整分层图、跨实例同步图、失败模式矩阵见 02 架构设计 §1 / §8 / §16。


4. 核心流程图

sequenceDiagram
    participant U as 用户
    participant PG as push-gateway
    participant R as Redis
    participant MSG as msg 服务

    U->>PG: WebSocket /ws?token=JWT
    PG->>PG: JWT RS256 校验via JWKS
    PG->>HUB: Register(userID, conn)
    HUB->>R: SADD edu:push:online:<userID> + EXPIRE 60s
    PG-->>U: 连接建立
    Note over PG: RFC 6455 Ping/Pong 30s60s 无帧断开

    MSG->>PG: POST /internal/push {user_id, event, data}
    PG->>HUB: SendToUser(userID, msg)
    alt 本实例有此用户
        PG->>U: WebSocket 推送
        PG-->>MSG: {delivered:true, online:true}
    else 本实例无此用户
        PG->>R: SMEMBERS edu:push:online:<userID>
        alt 用户在线(其他实例)
            PG->>R: PUBLISH edu:push:channel:user.<userID>
            R-->>PG: 持有实例订阅后投递
            PG-->>MSG: {delivered:true, online:true}
        else 用户离线
            PG-->>MSG: {delivered:false, online:false}
            Note over MSG: msg 走离线推送SMS/邮件)
        end
    end

5. 对外契约

5.1 HTTP 端点

方法 路径 鉴权 用途
GET /ws JWT RS256query ?token=Authorization: Bearer WebSocket 升级
POST /internal/push X-Internal-TokenISSUE-002 定向推送
POST /internal/broadcast X-Internal-Token 广播
GET /internal/online/<userID> X-Internal-Token 查在线状态
GET /healthz liveness 探针
GET /readyz readiness 探针软失败ISSUE-058
GET /metrics Prometheus 指标

5.2 Kafka 消费

Topic Consumer Group Message 说明
edu.notification.requested push-gateway NotificationRequested ISSUE-053 重命名(原 edu.notification.events
  • 至少一次 + Redis SETNX 幂等去重event_idTTL 24h
  • 失败重试 3 次后入 DLQedu.notification.requested.dlq

5.3 Redis 数据结构

Key 模式 类型 TTL 用途
edu:push:online:<userID> SETinstanceID 60s 在线用户所在实例集合
edu:push:channel:user:<userID> Pub/Sub 跨实例定向推送
edu:push:channel:broadcast Pub/Sub 跨实例广播
edu:push:idempotent:<event_id> SETNX 24h Kafka 幂等去重

无 gRPC 服务ISSUE-007push-gateway 仅暴露 HTTP + WebSocket不实现 gRPC 服务,packages/shared-proto/proto/ 无 push-gateway.proto。


6. 依赖关系

  • 上游msg 服务HTTP /internal/* + Kafka 事件)
  • 下游Redis在线 SET + pub/sub 跨实例同步、iamJWKS 公钥)
  • 客户端teacher-portal、student-portal、parent-portal、admin-portalWebSocket 连接)
  • 共享包shared-gotracer/logger/env/jwks

7. 架构约束

  1. 无业务逻辑,仅做连接管理与消息转发
  2. 无 DBISSUE-005审计/落库/重试由 msg 负责
  3. 仅 WebSocketISSUE-001不支持 SSE
  4. 无 gRPCISSUE-007仅 HTTP + WebSocket
  5. 连接鉴权必须校验 JWT RS256DevMode 接受 dev-token
  6. RFC 6455 控制帧心跳Ping/Pong 30s60s 无帧断开)
  7. 单用户连接数上限 5默认可配 MAX_CONNS_PER_USER
  8. 单实例容量 10w+ISSUE-003原 50k 已提升)
  9. Redis 故障软失败ISSUE-058/006/readyz 返 200 + degraded:true,不断本地 WebSocket
  10. Redis online SET 启动重建ISSUE-058先 SREM 旧 instanceID再基于内存重建

8. 关键 ADR完整见 02 §14

ADR 决策 来源
ADR-001 仅 WebSocket不支持 SSE ISSUE-001
ADR-002 X-Internal-Token 命名 ISSUE-002
ADR-003 单实例 10w+ 连接 ISSUE-003
ADR-004 无 DB审计由 msg 负责 ISSUE-005
ADR-005 Kafka topic edu.notification.requested ISSUE-053
ADR-006 /readyz 软失败 ISSUE-058/006
ADR-007 Redis SET 启动重建 ISSUE-058
ADR-008 Redis 必需但软失败 ISSUE-055 vs 058
ADR-009 纯 HTTP + WebSocket无 gRPC ISSUE-007
ADR-010 shared-go 复用 ARB-015 §17.5

9. 环境变量

变量 默认值 说明
PUSH_GATEWAY_PORT 8081 HTTP 监听端口
DEV_MODE false 开发模式(跳过内部鉴权,接受 dev-token
JWT_SECRET DevMode 有默认) JWT 密钥(生产必填)
JWKS_URL http://localhost:50052/.well-known/jwks.json iam JWKS 端点
INTERNAL_API_TOKEN (生产必填) /internal/* 鉴权 tokenISSUE-002
REDIS_URL redis://localhost:6379/0 Redis 连接 URL
KAFKA_BROKERS localhost:9092 Kafka broker 列表(逗号分隔)
KAFKA_NOTIFICATION_TOPIC edu.notification.requested 消费 topicISSUE-053
KAFKA_CONSUMER_GROUP push-gateway consumer group
WS_ALLOWED_ORIGINS (空) WebSocket Origin 白名单(逗号分隔)
MAX_CONNS_PER_USER 5 单用户最大连接数
HEARTBEAT_INTERVAL_SECONDS 30 心跳间隔
INSTANCE_ID hostname 实例标识Redis SET 成员)
OTEL_EXPORTER_OTLP_ENDPOINT localhost:4318 OTLP 端点