一篇读懂长连接网关:百万连接的架构账

长连接与短连接的根本差异

HTTP 短连接:请求-响应-断开——服务器不记住客户端——百万用户的 HTTP 是「百万次的瞬时请求」(可以负载均衡到任意机器)。长连接(WebSocket/TCP 长连):连接建立后保持——「服务器记住每一个连接」——百万连接 = 某台机器上挂着 10 万条活的 TCP——「连接的状态」让长连接网关与 HTTP 服务是两种架构:HTTP 可以无状态水平扩展;长连接网关的连接是有状态的——「有状态」是长连接架构一切复杂度的根源——连接在哪台机器上、怎么找到它、怎么推送给它。

这篇拆解长连接网关的架构账:单机极限、分层架构、连接寻址、推送链路。

单机的极限:一台机器能挂多少连接

连接数的物理极限推算:内存的推算:每条 TCP 连接的内核开销(socket 缓冲区(发送+接收缓冲——「每连接的内存」:默认配置下约 10-50KB(可调——10 万连接 = 1-5GB 内存的缓冲区——「缓冲区的调优」(小缓冲的设置(按业务的消息大小调——「100 万连接」的内存需求:10-50GB——服务器的内存可承受——「CPU 的推算」:连接的心跳与消息处理(心跳每 30 秒一次——百万连接的心跳 QPS = 3 万/秒——「心跳的处理成本」——CPU 可承受——「文件描述符的极限」:ulimit 与内核参数(「fd 的调优」(fs.file-max、somaxconn、tcp_mem——「系统参数的清单」是长连接服务器的第一步。「理论极限」与「实践极限」:理论(百万连接可行(C10M 的讨论)——实践(「业务消息的处理」才是瓶颈(连接只是挂着不难,难的是每条连接上的业务消息——「连接数的极限」按业务消息量重新推算——百万连接 × 每秒一条消息 = 每秒百万消息的处理——这才是真正的瓶颈——「连接上限」的公式:min(内存极限, CPU 处理极限, 业务要求)。

单机的优化技术:epoll 的事件驱动(库内操作系统内功篇——百万连接的非阻塞 I/O——「Netty 的事件模型」(Java 生态的 Netty(「Netty」是 Java 长连接的事实标准——「Go 的 goroutine」(每连接一个 goroutine 的模型——「Go 与 Java 的长连接」对比——「语言的选择」影响架构。「压测的必要性」:理论推算后必须实测——「长连接压测的方法」(模拟客户端、心跳+消息的组合压测——「压测的目标」:找到单机的真实极限——「单机极限」是架构设计的输入。

百万连接的分层架构

架构的分层:接入层(Gateway)+ 逻辑层(Logic)+ 推送层(Push)——「接入层」:只管连接的保持(连接的建立、心跳、消息的转发——「接入层的极简」(接入层不做业务逻辑——「接入层的轻」让它可以挂最多的连接——「接入层的扩容」(连接的有状态——扩容时新连接分到新机器(「新连接进新机器」——老连接自然流失到新机器——「连接的自然迁移」——不需要迁移存量连接。「逻辑层」:业务逻辑的处理(消息的存储与分发——「逻辑层的无状态」(逻辑层可以水平扩展——「接入层有状态 + 逻辑层无状态」的分层——「有状态的隔离」在接入层——有状态的复杂度被压缩到最小的一层。「推送层」:消息推送到目标用户的连接——「推送的寻址问题」:用户 U 的连接在哪台接入机器上——「连接注册表」(用户 → 接入机器的映射——「注册表」的实现:Redis(user → gateway_ip 的映射——「注册表的更新」(连接建立时写注册、断开时删——「注册表的一致性」(断线未及时清理——「心跳的注册维护」(心跳时刷新注册——「注册表」是推送寻址的核心。

graph TD
    A[百万连接分层架构] --> B[接入层 Gateway<br/>连接保持 · 心跳 · 转发]
    A --> C[逻辑层 Logic<br/>无状态业务处理]
    A --> D[推送层 Push<br/>寻址 + 投递]
    D --> E[连接注册表: user → gateway<br/>Redis 存储]
    F[连接寻址] --> G[查注册表 → 找到接入机 → 推送]

消息推送的链路与可靠性

推送的链路:消息产生(用户 A 发给用户 B)→ 逻辑层处理(存储消息)→ 推送层查询 B 的连接注册表 → 找到 B 的接入机 → 「跨机推送」:推送层把消息发给 B 所在的接入机(「接入机之间的路由」(推送层 → 接入机的转发——「推送层的转发」——接入机找到 B 的 socket 投递——「推送链路的三跳」:逻辑层→推送层→接入层——「链路的延迟」(三跳的延迟叠加——「推送的优化」(接入机直推(逻辑层直接通知接入机——「减少一跳」的架构变体——「推送链路的复杂度」与「跳数的权衡」。推送的可靠性:「消息丢失的场景」:B 的连接刚断(推送失败——「离线消息」的兜底(消息先存储、连接恢复后拉取——「推拉结合」(「推拉结合」的模式(在线推送+离线拉取——「推送的到达率」不可能 100%——「客户端的拉取兜底」(客户端定期的消息同步——「推拉结合」是 IM 的标准架构(推送给实时性、拉取给可靠性——「消息 ID 与去重」(推送可能重复(客户端去重——「去重」的机制(消息 ID 的客户端缓存。「多端同步」:一个用户多设备(手机+电脑——「多端的推送」(同一用户的多条连接——「多端的消息同步」(已读状态的多端同步——「多端同步」的序列号机制(每个用户一个递增序列号——「序列号」的多端对齐——「多端同步」是 IM 架构的深水区。

长连接的「心跳与保活」:心跳的作用(保活(NAT 超时的防止、断线的检测——「心跳的间隔」(移动网络 NAT 的超时(几分钟——「心跳间隔」的电池考量(频繁心跳耗电——「智能心跳」(按网络状态调整心跳间隔——「心跳的处理」(心跳不产生业务——「心跳的成本控制」。「断线的重连」:客户端的重连策略(「重连的退避」(指数退避——「重连风暴」(服务端故障恢复后百万客户端同时重连——「重连风暴」的防护(重连的随机延迟(「抖散重连」——客户端的重连加随机延迟——「服务端的连接限流」(重连风暴时的准入控制)。

长连接网关高频问答

收尾前回答三个高频问题。「接入层怎么做到轻量?」——接入层只做三件事:「接入层的极简」:连接管理(「连接的生命周期」(建连、心跳、断开)、消息转发(「转发」的格式(二进制协议——「业务解析不做」——不做鉴权细节(「鉴权的位置」(鉴权在逻辑层——接入层验 token 一次——「鉴权的轻量」——「接入层的协议」(私有协议 vs 标准 WebSocket——「私有协议」的高效——「标准协议」的兼容——「接入层的更新频率」(越少越好——「接入层的稳定」是连接不抖的前提。「连接注册表的 Redis 会不会成为瓶颈?」——注册表的架构:「注册表的读写量」:写(连接与断开——「注册的写量」(百万连接的心跳刷新——「心跳刷新注册」的成本——「注册表的优化」(本地缓存+Redis——「注册的延迟容忍」(「推送失败重试」的兜底——「注册表的一致性」要求不高——「最终一致即可」——「注册的过期」(TTL 的自动清理——「注册的 TTL」设计。「用户在线状态怎么维护?」——在线状态的架构:「在线状态的精度」:精确在线(连接在即在线——「连接与登录」的区别(「登录态」与「连接态」——「多设备」的在线(「多端在线」的状态——「在线状态的服务」(查询某用户是否在线——「在线查询」的接口——「在线状态的延迟」(「准实时」的容忍——「在线状态」的业务价值(「在线」的展示——「状态服务的成本」与价值权衡。长连接网关的问答收束:长连接网关的三个心智模型——「接入层是前台接线员(只管接通)、注册表是前台电话簿(找人在哪)、逻辑层是后方办公室(干活的)」——「接线员越轻、能接的电话越多」——「电话簿准不准决定找人快不快」**——百万连接的架构,就是把「接线」与「干活」分得足够开、把「找人」做得足够快。

网关的高频问答

收尾前回答两个高频问题。「接入层怎么做到轻量?」——接入层只做三件事:「接入层的极简」:连接管理(建连、心跳、断开)、消息转发(二进制协议)、不做业务解析——「鉴权的位置」(鉴权在逻辑层——接入层验 token 一次——「接入层的协议」(私有协议 vs 标准 WebSocket——「接入层的稳定」是连接不抖的前提。「连接注册表的 Redis 会不会成为瓶颈?」——注册表的架构:「注册的写量」(百万连接的心跳刷新——「注册表的优化」(本地缓存+Redis——「注册的延迟容忍」(推送失败重试的兜底——「最终一致即可」——「注册的过期」(TTL 自动清理。网关的问答收束:长连接网关的三个心智模型——「接入层是前台接线员(只管接通)、注册表是前台电话簿(找人在哪)、逻辑层是后方办公室(干活的)」——百万连接的架构,就是把「接线」与「干活」分得足够开、把「找人」做得足够快。

小结

长连接网关的架构账:单机极限(内存 10-50KB/连接的推算、fd 的系统调优、真正的瓶颈是业务消息量而非连接数——压测定极限);百万连接的分层(接入层轻量有状态+逻辑层无状态+推送层的寻址——「有状态的隔离」在接入层——新连接进新机器的自然迁移);连接寻址(注册表 user→gateway——心跳维护一致性);推送链路(三跳的寻址投递、推拉结合——推送给实时、拉取给可靠、消息 ID 去重、多端同步的序列号——「多端同步」是 IM 架构的深水区);心跳与重连(智能心跳的电池考量、重连风暴的抖散防护)。长连接网关的设计哲学:把「有状态的复杂」压缩到接入层,把「无状态的简单」留给逻辑层——百万连接的架构不是魔法,是把「状态」管理得足够克制。

长连接网关记住的每一个连接,都是架构必须负责到底的承诺——百万连接的背后,是一套把状态管理到极致的分层体系。

← 返回资讯列表

读者留言

COMMENTS 暂无
仅本站原创文章开放留言 · 请勿留下手机号、邮箱等个人信息

还没有留言,来说第一句?