长连接网关设计
2026/4/9大约 23 分钟
长连接网关设计
模块背景
Plato 为保证消息的及时性需要使用tcp长链接与客户端进行通信(节省DNS,握手等开销,并可主主动push消息给客户端),但长链接服务端需要一直维护连接状态。 连接状态通常分为系统部分和应用部分,系统部分指的是socket的管理,应用部分指的得是连接过程中的uid/did/fd 之前的映射关系,以及clientID等信息的存储。
这些信息的生命周期是跟随一个长连接的创建而产生,长链接的断开而消亡极易变化,持久化存储除了用于数据分析,同时这些信息也是收发消息维度的访问频率,QPS极高,因此需要存储在内存中被使用。
这就导致整个长链接服务是一个有状态服务,难以运维和管理,业务需求的频繁上线会造成系统的重启更新,长链接势必会断开,客户端将有所感知,影响用户体验。因此,必须将长连接收发消息的功能和状态维护一个统一的服务,尽可能减少其重启的频率,保证其稳定性和收发消息的延迟。
这就是接入层的由来,而接入层的核心组件就是长连接网关
消息链路流程
当客户端初始化建立长链接时
- 向某个IP的长连接服务发送创建连接信令。
- 网关server解析信令得知其为创建连接信令。
- 网关server,获得底层socket的FD,以及用户的uid/did,建立注册表。
- 回复客户端连接建立成功。
当客户端发送消息时
- 客户端发送上行消息信令。
- 网关服务接收到消息,并解析信令为上行消息信令。
- 根据clientID和sessionID进行路由,分配seqID等状态更新逻辑。
- 然后转发给业务层服务处理,确认业务层收到消息后立即回复客户端ACK。
当业务处理后,将消息转发给接收客户端时
- 业务根据sessionID定位到该会话的接收者的连接在哪一个网关服务上。
- 然后将消息通过RPC交给网关服务,网关拿到数据后通过uid对应connID,确定fd。
- 然后根据fd找到对应的socket,将消息拼接固定消息头发送给接收方客户端。
当连接断开的时
- 心跳超时,连接断开/异常断开
- 状态回收释放
长链接方案选型
| 方案 | 收益 | 代价 |
|---|---|---|
| 写死 ip 列表 | 实现简单 | 毫无扩展性,更新扩展需要发版一旦IP被监控,没有兜底手段 |
使用httpDNS服务 ![]() | 可以水平扩展长连接网关精准调度防止劫持实时解析 | 不能针对长连接来做精准调度httpDNS本身也会带来可用性问题 |
| 自建一个http server作为ip config server 通过一个域名+https协议访问 ipconfig 服务从中获得一批IP列表(减少请求&负载均衡&快速重连)客户端通过ip列表直接tcp连接长连接网关 | 自建http server 提供更高的可靠性基于业务场景做智能调度策略 | 不能避免 loaclDNS 劫持等问题 |
| httpDNS + ip config httpDNS 解析获得正确的http server 的公网ip地址然后通过此ip地址访问ip config server获得ip 列表 | 解决loacDNS问题实现长连接精准调度 | |
![]() |
并发通信模型方案选型
| 方案 | 收益 | 代价 |
|---|---|---|
两个协程监听两个channel实现全双工+一个定时器协程 goim 一个线程监听accept从accept socket返回创建连接消息服务端对这个fd 创建两个协程分别负责收发消息每发送一个消息创建一个定时器对象并阻塞一个协程![]() | 实现简单,开发迅速基于出色go协程机制,也可以支持百万用户聊天(加机器) | 内存占用高,难以突破单机C10M的瓶颈资源占用多将导致协程调度开销大,导致延迟升高一个协程占用4k内存,几万长连接时超过64G机器九有可能OOM每个下行消息都会创建一个定时器和协程,群里,push场景很容易OOM |
一个协程使用select实现轮询阻塞 一个conn对象创建后,分配一个协程阻塞在conn的read 和 send 两个channel上在一个select语句上轮询两个channel,谁有消息到来就去处理谁的逻辑业务回调时,开辟一个协程通过注册表找到send channel,交给连接处理协程发送消息![]() | 节省了一个协程的开销,内存占用减少三分之一协程数量减少三分之一,runtime调度开销减少,延迟有所提降低 | 同一时间只能接收或发送消息,群聊场景延迟升高协程的阻塞和唤醒在消息收发场景下依旧是瓶颈依旧没有解决下行消息时定时器和协程内存问题 |
goroutine pool 一个协程阻塞监听socket的read函数有信令到达后解析并处理业务层回调时,也是取goroutine pool取一个用来处理向socket send 消息。![]() | 业务层回调函数,使用协程池化技术,减少了协程的调度开销限制了协程资源的上界,避免协程分配过多导致OOM | 还是会有一个协程被阻塞需要维护conn的索引,才能让从协程池中获得的协程找到socket还是单工 |
reactor+goroutine pool 端到端设计原则 通过epoll 系统调用,将收发消息完全事件化当epoll读来临时,从goroutine pool中拿到消息并解析后转发当业务层回调的时候,直接从goroutine pool中拿到一个goroutine来处理逻辑![]() | 收发消息无协程阻塞,减少了调度开销与内存占用 |
长连接状态存储方案选型
| 方案分类 | 优化点 | 核心思想 | 具体措施 | 收益 | 代价 |
|---|---|---|---|---|---|
| 单点服务:状态映射表 | ![]() | 中心化存储连接状态,通过UID/DID反向路由 | 1. 维护fd/clientID/飞行队列/定时器2.维护 uid/did 到 connect对象所在机器 endpoint 3. 倒排维护 sessionID→connID→connect对象 4. 业务层通过 sessionID→uid→endpoint路由 | 点查性能高 实现简单 | 1. 飞行队列/定时器内存占用大 2. 网络扇出问题(群聊场景) 3. 定时器需协程维护 |
飞行队列优化![]() | 用Redis替代本地飞行队列 | 使用Redis List存储飞行队列,时间轮算法替代原生堆实现 | 减少网关内存消耗 协程规模从线性变为常数 | 内存仍然要维护时间轮数据结构 | |
| 微服务拆分:将服务拆分为:State Server和getway | 解耦网关与状态管理 | 1. 网关仅维护connID→fd映射2. connect对象中定时器,飞行队列等状态交给完全独立的state server维护,与网关server之间通过RPC进行通信 3. 业务层通过State Server控制收发逻辑 | 网关内存节约 ,可靠性提升, 重启次数减少 | 1. 增加RPC网络调用群聊场景下,会造成消息风暴。 2.业务层通过sessionID查到uid list,再跳到conn所在的机器上发送消息,依旧有高扇出问题 3. State Server设计复杂度上升 | |
| 容器绑定,同机部署 | 降低State Server与网关的网络开销 | 1,State Server与Gateway两个docker部署在同一个宿主机或物理机,改变宿主机两个docker的网络模式和协议栈,优化二者通信2.State server 可以设计成无状态的,使用中心化存储,做到存储计算分离,计算层无状态可水平扩展 | 1.减少了state 与 gateway通信的网络开销 2.使用两个docker隔离资源,可独立部署,进而保证可靠性同机部署,网络延迟消耗可忽略 | 1.造成服务之间相互依赖。扩展性降低,两个进程之间会共享os进而资源共享,导致可靠性降低 2.无法应对机房级故障 | |
| 资源回收 | 拆分Ip config,进行客户端无感知的调度重连 | 当单机持有一定数量的连接后,为避免资源被耗尽,会主动关闭最早接入的连接客户端收到连接后,会静默(客户端无感知)的进行重连Ip config 负责调度到新的gateway server上后台启动一个运维任务,周期的扫描情况长时间空闲的连接(需要根据业务场景决策) | 避免了资源耗尽OOM等问题 | 需要耗费额外的存储空间存储连接建立的时间戳 | |
| 分布式定时任务系统 | 独立定时任务系统 | 通过MQ异步通信,用来做飞行消息/心跳/连接重连等计时任务提供注册定时任务接口,告知定时时间,以及回调token提供异步的定时任务消息触发机制,gateway可感知到定时任务到期,并根据回调的消息进行逻辑处理,例如: 消息发送出去后,将飞行消息和定时时间打包成一个task注册到分布式定时任务系统中,然后到期后,通过回调接口将飞行消息发送给网关,网关自行重发,并再次计时。并且任务系统还要提供定时任务的取消功能,来应对心跳的重置逻辑。 | State Server无状态化。可以水平扩展,没有负担路由 | 1. 系统复杂度增加 2. 依赖MQ稳定性 3. 定时精度挑战 |
长连接服务感知方案选型
消息分发技术方案对比表
| 方案分类 | 具体方案 | 核心思想 | 收益 | 代价 |
|---|---|---|---|---|
| 广播路由策略 | 全扇出(Pub/Sub)![]() | 利用Redis的Pub/Sub功能或MQ订阅所有长连Server(MQ也可),业务服务将消息推送至消息总线;总线将消息分发给所有长连服务,附带Session和UID/DID信息;各长连服务检查本地是否存在对应Session的Socket(排除发送者),存在则发送,否则忽略。 | 1. 业务侧分发逻辑简单2. 无需维护全局状态3. 群聊/Push场景无效请求少,整体吞吐量高 | 1. C2C或小群聊场景存在大量无效分发2. 高无效网络调用占用带宽与协程资源,可能导致延迟增加或OOM3. 跨DC广域Push不可行 |
一致性Hash![]() | 基于服务发现机制,业务服务感知长连网关节点数量,通过一致性Hash算法将用户绑定到固定网关节点;创建连接时采用相同Hash算法确保用户长连固定在某一机器。 | 1. 性能优异2. 支持弹性扩展,避免分片不均 | 1. IP配置服务器调度灵活性受限2. 群聊场景优化效果有限 | |
| 精确路由策略 | 映射路由表(独立服务)![]() | 独立路由服务集群维护多级映射关系: - SessionID → UID列表 - UID → DID列表 - DID → ConnID列表 - ConnID → Endpoint映射 创建连接时路由服务建立SessionID到Endpoint的倒排索引,业务服务通过RPC查询Endpoint并分发消息。 | 1. 精准传输零冗余2. 内存操作高性能3. 支持多业务隔离 | 1. 群聊/Push场景大规模扇出时查询冗余2. 额外网络跳数增加通信复杂度3. 跨DC广域Push不可行 |
State Server集中路由![]() | State Server统一管理路由信息,业务服务仅需传递SessionID,由State Server自主定位具体长连网关并分发消息。 | 1. 减少网络调用次数2. 端到端延迟降低 | 1. State Server复杂度显著提升2. 可靠性风险增加3. 跨DC广域Push不可行 | |
| 混合路由策略 | 组合策略 | 混合使用两种模式: - C2C/小规模群聊采用精确路由(路由服务查询)- 大规模活跃群采用全扇出(Pub/Sub广播)。 | 1. 动态平衡资源消耗2. 场景适配灵活 | 实现复杂度高 |
| 地理路由策略 | 基于地理位置调度 | 根据用户IP等地理位置信息,将相邻用户分配至同一网关Server。 | 1. 同城社交/O2O场景延迟优化2. 区域性服务体验提升 | 1. 路由策略单一化2. 实现复杂度高 |
| 社交图谱路由策略 | 社交关系图计算 | 离线或近线计算用户社交关系网络,综合会话活跃度权重分配最佳节点: - 将高频活跃聊天的用户聚集到同一长连网关- 维护Session到Endpoint的倒排索引加速查询。 | 1. 广域Push路径最优2. 性能调优空间大 | 1. 实现复杂度极高2. 需持续维护动态关系模型 |
| 基础设施优化 | 弱网感知调度 | 监控网络质量(如延迟、丢包率),动态选择最优数据中心节点建立连接。 | 1. 弱网环境下用户体验保障 | 数据中心建设及运维成本高昂 |

断线重连方案选型
| 方案分类 | 具体方案 | 核心思想 | 收益 | 代价 |
|---|---|---|---|---|
| 连接稳定性优化 | 租约机制 | 客户端与服务端建立长连接心跳(端到端设计): - 客户端发起心跳降低服务端性能开销 - 服务端维护连接超时计时器,超时后主动断开连接回收资源 - 心跳成功则重置计时器 - 收发消息可替代心跳减少频次 - 附心跳机制示意图: ![]() | 1. 保证端到端连接可靠性2. 实现简单逻辑清晰3. 避免运营商截断空连接风险 | 1. 弱网下极易断连导致资源浪费2. 运营商路由器空闲连接限制3. 心跳引发流量潮汐可能压垮服务 |
| 容灾恢复机制 | 断线重连 | 断线重连机制设计: - 连接断开或心跳超时后启动重连计时器 - 计时到期前重连成功则复用状态(更新路由表) - 重连优先使用原IP网关,失败后切换IP配置列表 - 随机等待时间分散流量 - 附重连流程示意图: ![]() | 1. 缓解弱网环境频繁断连问题2. 减少资源释放与创建开销 | 1. 弱网判定阈值固定无法动态适配2. 流量潮汐问题未彻底解决3. 跨网关状态复用能力有限 |
| 冗余连接策略 | 主备连接 | 维护双长连接通道: - 主连接用于常规消息收发 - 备用连接用于PUSH等场景 - 主连接断开时自动降级为备用连接 - 上行消息失败时切换为HTTP POST请求 ![]() | 1. 降低用户连接中断感知2. 保障下行消息可达性 | 1. 实现复杂需维护双连接逻辑2. 跨网关状态同步成本高3. 无备用连接时需独立维护长连成本过高 |
| 协议弹性机制 | 协议升降级 | 动态协议切换策略: - 弱网环境下TCP降级为QUIC/SPDY - 进一步降级为HTTP协议(去除TLS握手) - Gateway仅解析固定消息头,剩余字节交State Server解析 | 1. 提升弱网环境连接成功率2. 规避TCP协议缺陷(队头阻塞等)3. 优化加密传输性能 | 1. QUIC依赖UDP协议成熟度不足2. 缺乏非对称加密安全性3. 协议切换实现复杂度高 |

减少长连接服务的崩溃/重启次数,实现永不宕机方案选型
| 方案分类 | 具体方案 | 核心思想 | 收益 | 代价 |
|---|---|---|---|---|
| 进程隔离策略 | 运行时隔离 | 将Gateway与State Server拆分为独立进程运行,通过进程级隔离实现: - 网关进程与服务进程解耦 - 故障隔离避免相互影响 - 支持分层部署(同机/跨机) | 1. 降低服务重启频率2. 灵活部署提升资源利用率3. 增强系统容错能力 | 1. 跨机器部署时网络调用增加2. 部署复杂度上升3. 同机部署才能最大化网络性能优势 |
| 状态持久化策略 | 共享内存 | State Server将状态数据写入共享内存(mmap机制): - 进程崩溃后可快速从共享内存恢复状态 - 避免磁盘IO带来的恢复延迟 | 1. 减少崩溃导致的业务中断时间2. 提升故障恢复速度 | 1. 共享内存管理复杂度增加2. 数据一致性保障难度上升3. 内存占用量可能翻倍 |
| 服务热升级策略 | 长连接平滑重启 | 通过双进程接力实现无感重启: - 新进程注册监听后与老进程建立Unix Domain Socket通信 - 同步历史连接状态(FD/映射关系) - 逐连接迁移后释放老进程资源 - 支持跨进程文件描述符传递 | 1. 客户端完全无感知重启2. 避免流量潮汐冲击3. 支持在线升级 | 1. 单机万级连接迁移耗时过长2. 跨机房迁移不可行3. 实现复杂度高(需处理锁/序列化/状态同步) |
| 服务终止策略 | 优雅关闭 | 通过信号触发有序退出: - 停止接受新连接请求 - 主动通知客户端下线并等待确认 - 完成连接释放后回收资源 - 支持与Ops Server联动控制 | 1. 用户无感知的服务下线2. 支持集群水平扩展3. 规范运维操作流程 | 1. 客户端交互流程复杂2. 异常case处理困难3. 下线时间不可控(可能无限延长) |
| 跨机迁移策略 | 扩缩容迁移 | 基于Redis启发的连接迁移方案: - State Server规划连接迁移计划 - 新旧网关建立双写通道 - 客户端重建连接并同步状态 - 原网关释放资源 - 支持跨数据中心迁移 | 1. 支持在线扩容/缩容2. 最小化连接中断时间3. 解决长连网关扩展瓶颈 | 1. 实现复杂度极高(需处理网络分区/状态同步)2. 依赖客户端配合3. 状态迁移过程易出错需人工干预 |
| 运维自动化策略 | 独立Ops Server | 构建专用运维决策系统: - 实时采集业务指标(CPU/内存/连接数/QPS) - 基于规则引擎触发运维操作 支持自动扩缩容/故障转移- 提供人工干预接口 | 1. 提升规模化运维效率2. 实现故障自愈能力3. 规范运维操作标准 | 1. 小规模场景收益不明显2. 系统复杂度倍增3. 初期研发成本较高 |

限流/熔断/降级 方案选型
| 方案 | 核心思想 | 收益 | 代价 |
|---|---|---|---|
| 基于服务发现 | 通过服务发现机制分发分布式限流配置: - 将全局限流规则同步至各单机节点 - 单机采用令牌桶/漏桶算法执行本地限流 - 支持动态更新配置(附配置同步流程图)链接 | 1. 防止突发流量压垮系统 2. 实现全局状态一致性管理 3. 降低单节点配置管理复杂度 | 1. 静态阈值难以适应复杂场景 2. 无法动态调整限流策略 3. 存在漏限/误限风险 |
| 负反馈调节 | 基于近线采样的日志分析实现闭环控制: - 采集连接断开率/失败率/RTT等指标 - 通过算法模型(如PID控制器)计算最优阈值 - 动态推送参数至网关节点 - 支持实时运维干预(附算法决策流程图) | 1. 动态优化限流阈值 2. 自动修复漏限/误限问题 3. 减少人工干预成本 | 1. 实现复杂度高(需算法工程化) 2. 模型训练数据质量依赖性强 3. 实时性受反馈周期限制 |
| 多目标融合 | 综合多维度指标进行限流决策: - 监控连接成功率/心跳RTT/内存/CPU/协程池状态等20+指标 - 建立加权评分模型计算节点权重 - 通过IP Config Server下发最优节点列表 - 支持客户端重连重试策略(附多指标融合公式) | 1. 系统稳定性最大化 2. 避免单一指标决策偏差 3. 支持复杂网络环境自适应 | 1. 指标关联性分析复杂 2. 融合公式调优困难 3. 实时计算资源消耗大 |

长连接服务中台化,产品化,实现通用性方案选型
| 方案分类 | 具体方案 | 核心思想 | 收益 | 代价 |
|---|---|---|---|---|
| 业务隔离策略 | APP ID逻辑区分 | 通过APP ID实现业务方隔离: - 不同APP ID对应独立业务逻辑代码 - 部署独立集群实现资源隔离 - 支持多业务线并行运行 | 1. 实现简单易于理解 2. 基础资源隔离能力 3. 快速支持新业务接入 | 1. 业务扩展后系统复杂度指数级增长 2. 缺乏领域建模导致代码复用率低 3. 跨业务协同能力弱 |
| 消息路由策略 | 发布/订阅模式 | 基于领域建模构建消息通道: - 抽象网关为消息中间件(知乎长连网关设计) - 支持多对多订阅/广播模式 - QoS分级策略控制 - Token鉴权(ACL) - 动态Token下发与运行时资源隔离 | 1. 高灵活组合能力(生产者/消费者模式) 2. 支持复杂业务场景(通讯/上报/广播) 3. 实现中台化架构 | 1. 领域建模复杂度高 2. 代码复用性与业务匹配度需权衡 3. 高并发场景鉴权性能瓶颈 |
| 部署架构策略 | 单元化部署方案 | Pipeline模式实现模块化部署: - 独立集群(IP Config + Gateway + State Server) - Ops Server统一管理 - 可插拔Pipeline组件(业务自定义逻辑) - 混合/独占部署模式 | 1. 支持现有代码平滑升级 2. 模块化提升代码复用率 3. 资源隔离保障可靠性 4. 统一调度提升资源利用率 | 1. 需要完整接入文档指导 2. 存储一致性问题(读放大) 3. 写放大导致延迟增加 |
| 会话管理策略 | Session绑定策略 | 策略模式实现灵活分发: - 提供RPC回调让业务方实现绑定逻辑 - 吞吐优先(群聊)与延迟优先(C2C)双模式 - 本地内存维护Session-DID映射 - 业务层感知连接状态变更 | 1. 解决通用分发方案缺失问题 2. 兼顾群聊与C2C场景差异 3. 业务自主控制分发策略 | 1. 业务需深度感知网关状态 2. 维护Session映射增加复杂度 3. 跨业务状态同步挑战大 |

多IDC方案选型
| 方案分类 | 具体方案 | 核心思想 | 收益 | 代价 |
|---|---|---|---|---|
| 智能调度策略 | 基于连接调度策略 | 通过地理信息/社交关系/活跃会话关系分析: - IP Config Server动态下发最优IP列表 - 高频通信用户跨数据中心聚合 - 减少广域请求次数(附调度策略示意图) | 1. 广域请求数量降至最低 2. 下行消息P99延迟显著优化 3. 跨区域流量成本降低 | 1. 数据中心异常导致全局不可用 2. 用户关系实时计算延迟 3. 算法复杂度高(需处理动态权重计算) |
| 高可用架构策略 | 旁路化部署 | 构建IP Config Server多活架构: - 独立数据中心部署 - 多集群热备机制 - 故障时自动切换(附旁路架构图) | 1. 接入层可用性提升至P0级 2. 消除单点故障风险 3. 支持跨区域容灾 | 1. 多数据中心部署成本翻倍 2. 热备数据同步延迟增加 3. 配置一致性保障难度上升 |
| 传输优化策略 | 下行消息专线+MQ | 混合传输架构设计: - 中心化存储维护跨机房路由表 - DID-Endpoint映射多机房同步(含机房标识) - 跨机房通信走专属MQ通道 - 专线传输降低延迟(附专线拓扑图) | 1. 跨机房通信对业务透明 2. 专线保障传输质量 3. 架构改造平滑(兼容现有MQ体系) | 1. 专线建设成本高昂 2. 公网MQ传输存在抖动风险 3. 机房标识维护增加复杂度 |















