Skip to content

推送网关技术全景调研

「消息从服务器到用户手机屏幕,中间经历了什么?」


一、技术背景:从"一问一答"到"主动推送"

1.1 HTTP协议的"先天性缺陷"

理解推送网关,要先理解它解决的根本问题:HTTP协议天生不支持服务端主动推送。

HTTP请求-响应模型:

客户端 → 发请求 → 服务器
客户端 ← 收响应 ← 服务器

每次通信必须由客户端主动发起
服务器无法主动"找"客户端

这意味着:如果服务器有新消息,客户端只能一遍遍去问——"有没有新消息?有吗?有吗?有吗?"

这就是"轮询"(Polling)。

1.2 轮询时代:短轮询与长轮询

方案原理问题
短轮询(Short Polling)客户端每隔1-3秒发一次请求问"有新消息吗"大量无效请求,浪费带宽和服务器资源
长轮询(Long Polling)服务器"挂起"请求,直到有新消息才返回服务器长时间占用连接资源;每次都要重新建立连接

轮询就像不断敲门问"到了吗?" ——可以工作,但效率极低,用户体验差。

1.3 WebSocket的诞生:全双工实时通信

2011年,HTML5标准将 WebSocket协议(RFC 6455)正式纳入规范,结束了这场"敲门问话"的历史:

HTTP时代:                          WebSocket时代:
客户端 → 请求 → 服务器              客户端 ↔ 服务器
客户端 ← 响应 ← 服务器              (双向实时通道,常开)
客户端 → 请求 → 服务器               一次握手,长期保持
客户端 ← 响应 ← 服务器              服务器随时主动推送

WebSocket的核心原理——协议升级握手:

第一步:客户端发送HTTP"升级请求":
GET /chat HTTP/1.1
Upgrade: websocket          ← 关键:我要升级协议
Sec-WebSocket-Key: dGhlIHNhbXBsZ...  ← 随机密钥

第二步:服务器验证并响应:
HTTP/1.1 101 Switching Protocols  ← 关键:协议切换成功
Upgrade: websocket
Sec-WebSocket-Accept: s3pPLMBiTxaQ...

第三步:连接升级完成,后续数据全走WebSocket帧

1.4 移动端推送的独特挑战

Web端有WebSocket就能解决大部分问题,但移动端(iOS/Android)面临的挑战远比Web端复杂得多

平台推送机制核心挑战
iOSAPNs(Apple Push Notification service)App在后台被系统挂起,无法主动通信;依赖系统统一唤醒
Android(海外)FCM(Firebase Cloud Messaging)依赖Google服务框架,国内无法使用
Android(国内)各厂商通道(华为、小米、OPPO、vivo)无Google服务,各厂商深度定制ROM,后台限制极其严格

二、核心技术问题

问题一:长连接保活——"连接还活着吗?"

问题描述:TCP连接看似建立了,但实际上中间经过的NAT设备、防火墙、运营商网关,可能会在无流量时主动断开空闲连接(通常15-30分钟)。

场景:
客户端 → 与服务器建立TCP连接
用户放下手机去开会(30分钟内无操作)
防火墙/NAT认定连接已死 → 悄悄断开
服务器有消息要推送 → 发现连接已断 → 消息丢失

解决方案——心跳机制(Heartbeat)

心跳机制原理:
客户端每30秒发送一个心跳包(PING帧)
服务器收到后回复(PONG帧)
中间设备看到有流量 → 保持连接不被断开

智能心跳策略:
前台运行(App打开):心跳间隔 10-15秒
WiFi环境:心跳间隔 30-45秒
移动网络:心跳间隔 45-60秒(减少电量消耗)
检测到网络不稳定:缩短间隔,快速重连

问题二:进程保活——"App被系统杀了吗?"

问题描述:Android系统在内存紧张时,会优先杀掉后台应用。这意味着即便TCP连接建立着,如果App进程被杀了,连接就断了。

Android系统内存回收优先级:
后台进程(用户不可见)→ 随时可杀
空进程(无Activity/Service)→ 优先杀
系统进程 → 不杀

解决方案——多层次保活策略

层级策略说明
系统级厂商推送通道(华为、小米)系统级进程,系统不会主动杀
框架级前台服务(Foreground Service)显示持续通知条,保活优先级最高
调度级JobScheduler / WorkManager系统在合适时机批量执行任务
应用级自启动引导提示用户开启自启动权限

问题三:Android厂商通道碎片化

问题描述:这是国内Android推送最棘手的问题。没有Google Play Services,FCM完全不可用,国内各手机厂商各自维护自己的推送SDK,行为差异极大:

厂商SDK名称后台限制程度特殊要求
华为Push Kit严格需安装华为应用市场
小米Mi Push中等MIUI安全中心可设置白名单
OPPOOPPO Push严格需申请白名单
vivovivo Push严格系统级管控
荣耀Honor Push严格独立于华为系统

问题的核心:不同厂商的推送SDK行为不一致,有的设备能收到推送,有的收不到,排查成本极高。

问题四:WebSocket集群与会话共享

问题描述:WebSocket是有状态协议,一个客户端只与集群中某一个节点建立连接。当需要向某个用户推送消息时,消息必须路由到持有该用户连接的节点。

问题场景:
用户A → 连接节点1
用户A → 连接节点3
服务端发消息给用户A → 消息发到节点2
节点2:用户A不在这台 → 消息丢失!

解决方案——广播方案对比

方案原理优点缺点
注册中心方案所有节点上报连接状态到中心存储精确路由实现复杂,依赖中心存储
消息队列广播方案发一条消息,所有节点都收到,各自判断实现简单,轻量节点多时广播量大
Redis Pub/Sub订阅同一频道,节点收到广播实时性高不保证可靠送达

问题五:消息去重与跨端同步

问题描述:当用户同时在手机、平板、网页上登录同一账号,同一条消息通过长连接推送多次,会导致用户看到重复通知。

场景:
用户用手机和电脑同时打开App
收到消息 → 手机收到1次 → 电脑收到1次
用户看手机通知 → 电脑又弹一次通知 → 体验糟糕

解决方案——BroadcastChannel + 消息ID去重

javascript
// 每条消息携带唯一ID
const seenIds = new Set();

function handleNotification(notification) {
  if (seenIds.has(notification.id)) return; // 已有,跳过
  seenIds.add(notification.id);
  showToast(notification);
}

// 跨标签页协调:同一个标签页收到,其他标签页跳过
const channel = new BroadcastChannel("notifications");

function handleNotification(notification) {
  if (seenIds.has(notification.id)) return;
  channel.postMessage({ type: "claimed", id: notification.id }); // 广播"我处理了"
  showToast(notification);
}

channel.onmessage = (event) => {
  if (event.data.type === "claimed") {
    seenIds.add(event.data.id); // 其他标签页不再重复显示
  }
};

问题六:消息优先级与送达率保障

问题描述:并非所有消息都同样重要。支付失败、验证码这类"关键消息"必须送达,但社交动态、活动推送送达延迟一点也没关系。

解决方案——消息分级策略

优先级消息类型推送策略
Critical(关键)支付失败、安全警报WebSocket+推送双通道,立即送达,勿扰模式也要响
Important(重要)新消息、@提及WebSocket优先,断连后5-10秒走推送通道
Informational(普通)社交动态、活动通知仅WebSocket,离线不补发
Background(后台)配置更新、数据同步静默推送,App后台处理,不打扰用户

三、技术架构详解

3.1 整体架构图

┌─────────────────────────┐
│      业务服务器          │
│ (订单/聊天/支付/客服...) │
└───────────┬─────────────┘
            │ 写消息
┌───────────▼─────────────┐
│       消息队列           │
│   (Kafka / RocketMQ)    │
└───────────┬─────────────┘
            │ 消费
┌───────────▼─────────────┐
│       推送网关           │
│  ┌─────────┬─────────┐  │
│  │WebSocket│ HTTP    │  │
│  │  网关   │ 推送接口 │  │
│  └────┬────┴────┬────┘  │
└───────┼─────────┼───────┘
        │         │
   ┌────┼─────────┼────────────┐
   │    │         │            │
   ▼    ▼         ▼            ▼
┌──────┐┌──────┐┌──────┐┌──────────┐
│iOS   ││华为  ││小米  ││ Web端    │
│APNs  ││Push  ││Mi    ││WebSocket │
│      ││Kit   ││Push  ││          │
└──────┘└──────┘└──────┘└──────────┘

3.2 推送网关核心模块

模块职责技术选型
长连接管理维护与客户端的TCP连接,处理心跳、断线重连Netty(Java)/ Go / Node.js
会话管理记录每个用户/设备与哪个节点建立了连接Redis(分布式会话)
消息路由根据设备类型选择最优推送通道本地路由表 + 配置中心
消息队列解耦业务与推送,实现削峰填谷Kafka / RocketMQ
厂商通道对接对接APNs/FCM/华为/小米等厂商接口各大厂商SDK
监控报警监控送达率、延迟、错误率Prometheus + Grafana
消息存储离线消息持久化,连接恢复后补发MySQL + Redis

3.3 推送完整流程

步骤1:消息触发
  用户A在App发消息 → 业务服务器写消息到数据库
  业务服务器 → 写入消息队列(带目标用户ID)

步骤2:网关路由
  推送网关消费消息队列 → 查询目标用户的设备列表
  查询该用户有哪些设备在线(手机/平板/Web)

步骤3:多通道分发
  在线设备 → 通过WebSocket长连接推送(毫秒级)
  离线设备 → 根据设备类型路由到对应厂商通道
    iOS设备 → APNs
    华为设备 → 华为Push Kit
    小米设备 → Mi Push
    其他Android设备 → FCM

步骤4:送达确认
  设备收到消息 → 发ACK确认
  超时未ACK → 进入重试队列 → 指数退避重试
  多次重试失败 → 记录失败原因,触发报警

3.4 爱奇艺号WebSocket网关实战架构

爱奇艺号的实践提供了一个完整的生产级参考,其架构设计解决了四个核心痛点:

四大痛点

  1. WebSocket技术栈不统一(Netty/Web容器混用)
  2. 实现分散在各业务系统,强耦合
  3. 集群节点间会话不共享
  4. 缺乏业务含义的监控指标

架构方案

┌────────────────────────────────────────────────────────┐
│                 业务系统(HTTP调用)                     │
└────────────────────────┬───────────────────────────────┘
                         │ HTTP推送请求
┌────────────────────────▼───────────────────────────────┐
│              WebSocket长连接网关                         │
│  ┌──────────────────────────────────────────────────┐  │
│  │        SessionManager(内存会话管理)              │  │
│  │  ┌───────────────────────────────────────────┐   │  │
│  │  │  UserSession(用户维度)                    │   │  │
│  │  │  ChannelSession(设备/连接维度)            │   │  │
│  │  └───────────────────────────────────────────┘   │  │
│  └──────────────────────────────────────────────────┘  │
│                         │                               │
│                         ▼ 写入MQ                        │
│  ┌──────────────┐                                      │
│  │ RocketMQ     │ (广播模式)                          │
│  │ 广播消费     │                                      │
│  └──────────────┘                                      │
└────────────────────────┬───────────────────────────────┘

           ┌─────────────┼─────────────┐
           ▼             ▼             ▼
      ┌─────────┐  ┌─────────┐  ┌─────────┐
      │  节点1  │  │  节点2  │  │  节点3  │
      │ 5万连接 │  │ 5万连接 │  │ 5万连接 │
      └─────────┘  └─────────┘  └─────────┘

压测结果:单节点支持50万并发连接,总计100万+

四、关键技术选型对比

4.1 长连接协议对比

协议适用场景优点缺点
WebSocketWeb端实时通信全双工、轻量、广泛支持无持久化,断连需重建
MQTTIoT设备、移动端极轻量(2字节头部)、支持QoS、功耗低协议较复杂,需要Broker
Socket.IO快速原型、跨平台自动降级、兼容性好体积较大,有自定义封装
gRPC Streaming微服务间通信高性能、跨语言、标准化复杂度高,不适合公网推送
SSE(Server-Sent Events)单向推送(服务端→客户端)轻量、基于HTTP、自动重连仅单向,IE不支持

4.2 开源推送框架对比

框架开发语言特点适合场景
NettyJava高性能事件驱动,最成熟大规模生产环境
GoimGo轻量、高并发,字节跳动开源日活千万级App
MobileIMSDKJava/iOS/Android/小程序跨平台完整方案快速集成
OnePushAndroid多厂商通道统一SDK国内Android推送聚合

五、最新进展(2025—2026年)

5.1 多通道融合成为行业标准

2025年后,单一推送通道已无法满足业务需求,多通道融合成为行业共识:

传统方案:
  国内Android → 只接厂商通道 → FCM不可用时完全失效

融合方案(2026年主流):
┌─────────────────────────────────────────────┐
│          智能通道选择引擎                     │
│                                              │
│  设备上线 → 健康度检测 → 最优通道自动选择     │
│                                              │
│  检测华为可用 → Push Kit (主通道)             │
│  检测FCM可用 → FCM (备用通道)                │
│  检测自研通道 → 自建TCP长连接 (实时通道)      │
│                                              │
│  主通道失败 → 自动切换备用通道 → 无感知       │
└─────────────────────────────────────────────┘

5.2 AI驱动的推送优化

2025年起,头部厂商开始将AI能力引入推送系统:

方向具体应用效果
用户行为预测AI分析用户活跃时段,动态调整推送时间打开率提升30-50%
消息优先级智能判断NLP分析消息内容,自动分级减少无效推送,降低卸载率
送达率预测预测消息是否能成功送达,提前预警运维响应提前30分钟
异常检测AI识别异常送达率模式,自动诊断MTTR(故障恢复时间)缩短60%

5.3 鸿蒙生态推送:华为Push Kit新能力

2026年,华为Push Kit持续演进,新增三类高价值场景:

新能力场景突破点
实况窗推送打车/外卖/快递实时状态可折叠设备实时刷新,无需打开App
应用内通话推送视频通话、语音通话系统级通话体验,接通率大幅提升
卡片刷新消息打车状态、订单进度服务直达,减少跳转层级

5.4 统一推送协议探索:MQTT 5.0

2025年后,MQTT 5.0在移动推送领域的应用逐渐增多,相比MQTT 3.x有显著改进:

改进点说明对推送的价值
用户属性(User Properties)消息可携带自定义键值对推送元数据直接内嵌,无需解析消息体
主题别名(Topic Alias)减少主题名字节开销在高频推送场景节省30%带宽
原因码(Reason Code)明确的错误原因故障诊断效率大幅提升
消息过期(Message Expiry)消息可设置过期时间离线消息自动过期,无需手动清理

5.5 推送安全与合规

议题2026年新要求影响
隐私合规GDPR/CCPA/国内数据安全法趋严推送内容不得包含敏感个人信息
端到端加密高安全场景要求推送内容仅客户端可解密推送仅携带消息ID,正文由App拉取后解密
DDoS防护恶意刷Token攻击增加网关需实现Token请求限流(1000次/分钟/设备)

六、精华总结

推送网关的核心矛盾

用户期望:
  → 消息秒到、省电、不打扰

系统现实:
  → 网络不稳定、厂商限制、电量管控

推送网关的使命:
  → 在"用户期望"和"系统现实"之间,
     找到那个恰到好处的平衡点。

架构选型决策树

消息实时性要求?

├── 毫秒级(聊天、直播)→ WebSocket长连接 + 自研推送
│   → 多节点集群 + Redis会话共享

├── 秒级(订单通知)  → 厂商通道 + 长连接备用
│   → 华为/小米/APNs多通道聚合

└── 分钟级(日报推送)→ 厂商通道即可
    → 无需长连接,节省资源

参考资料

Move fast and break things