Apollo 技术文档Apollo 技术文档
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
  • MMORPG 架构 QA

Q25: 连接数上限由什么决定?如何突破 C10K 问题?

核心结论

连接数上限从来不是一个单独的“网络库指标”,而是操作系统、协议栈、内存、CPU、事件模型、业务负载共同决定的结果。

所谓 C10K,今天早已不是神秘门槛;真正难的是在高连接数下继续保证:

  • 延迟稳定
  • 广播可控
  • 心跳扫描不过载
  • 单连接异常不会拖垮整体

所以“能连上 1 万个 socket”和“能稳定服务 1 万个在线玩家”不是同一回事。

一、连接数上限到底受什么影响

1. 文件描述符和内核参数

每个连接都要占用系统资源,最直观的是:

  • 文件描述符上限
  • 监听 backlog
  • socket 缓冲区
  • 端口与内核网络参数

这些是基础门槛,但通常不是最终瓶颈。

2. 每连接内存成本

高连接数系统很容易被忽视的一点是“每条连接实际占多少内存”。

除了内核 socket 本身,还包括:

  • 发送缓冲
  • 接收缓冲
  • 会话对象
  • 定时器
  • 认证信息
  • 待发送队列

如果每连接多浪费几十 KB,上万连接时很快就是数百 MB 到 GB 级开销。

3. 事件模型和线程模型

如果仍然采用“一连接一线程”,C10K 很快会被线程栈、调度开销和上下文切换拖垮。

高连接数系统通常依赖:

  • epoll
  • kqueue
  • IOCP
  • 事件驱动或少线程 Reactor/Proactor 模型

4. 业务处理成本

连接数高并不一定可怕,可怕的是:

  • 每条连接都高频发消息
  • 每条消息都要复杂解码、鉴权、路由
  • 每次更新都触发大范围广播

很多 MMO 实际瓶颈并不在 accept 连接,而在连接建立后附带的业务负载。

二、为什么“一连接一线程”扛不住

这类模型的问题不是概念上不能工作,而是成本线性膨胀得太快:

  • 线程栈占内存
  • 调度器开销上升
  • 锁竞争加重
  • 空闲连接也要被线程管理

连接数一高,CPU 时间花在调度和同步上的比例就会越来越离谱。

所以 C10K 时代真正的突破点,是从阻塞式模型切到事件驱动多路复用模型。

三、今天讨论 C10K,重点已经变了

现代系统里,单机承载几万乃至更多长连接并不罕见。真正需要回答的是:

  • 这些连接是否都活跃
  • 心跳和超时扫描怎么做
  • 广播和路由怎么分摊
  • 慢连接怎么隔离
  • 网关和逻辑服是否解耦

也就是说,难点已经从“能否接 1 万连接”变成“如何在大规模连接下保持系统稳定”。

四、工程上怎么把连接数做上去

1. 使用事件驱动 I/O

这是前提。

典型做法是:

  • 少量 I/O 线程负责收发
  • 业务处理线程或逻辑线程解耦
  • 连接状态在事件循环里推进

这样可以显著降低线程数和调度成本。

2. 把接入层和业务层分开

MMO 常见做法是网关单独承载连接,业务服处理逻辑。

这样做的好处是:

  • 连接抖动不会直接冲击逻辑服
  • TLS、心跳、限流、压缩可集中处理
  • 网关可以横向扩展

如果逻辑服自己直接扛大量公网连接,扩容和故障隔离都会更难。

3. 控制每连接状态大小

这点很朴素,但非常关键。

常见优化包括:

  • 缩小会话对象
  • 避免每连接独立大缓冲区
  • 延迟分配重资源对象
  • 把少访问数据移出热路径

4. 管好慢连接

高连接数系统非常怕少量慢连接把发送队列拖爆。

需要明确策略:

  • 发送队列上限
  • 过期状态消息可覆盖或丢弃
  • 长期跟不上的连接主动断开

否则广播系统会被反压放大。

五、MMO 里连接数不是唯一指标

同样是 1 万连接,压力可能完全不同。

例如:

  • 1 万挂机连接,几乎只发心跳
  • 1 万人同屏战斗,高频状态广播
  • 1 万分散在线,AOI 内只有少量互动

这三种情况下,真正的瓶颈可能分别落在:

  • 心跳与定时器
  • 广播与序列化
  • 路由与状态同步

所以评估连接承载能力必须结合在线行为模型,而不是只看 socket 数。

六、如何继续从 C10K 走向更高规模

1. 水平扩展网关

把连接均匀分摊到多个接入节点,通常比在单机上无限挤压更现实。

2. 业务分区

让不同场景、房间、分片、逻辑域分散到不同节点处理,避免所有连接最终汇聚到同一逻辑热点。

3. 降低无效流量

包括:

  • AOI 裁剪
  • 批量发送
  • 压缩
  • 低优先级消息降频

减少单位连接的平均成本,往往比继续抠内核参数更有效。

4. 完整观测

必须持续观察:

  • 活跃连接数
  • 心跳超时数
  • 每连接收发速率
  • 发送队列堆积
  • 事件循环延迟
  • GC 或主线程卡顿

否则很难知道真实瓶颈在哪。

七、常见误区

1. 把 ulimit 调大就算解决 C10K

这只是入场券,不是最终答案。

2. 连接数越高,系统就越强

没有意义。更重要的是在目标业务模型下,系统是否还能保持稳定延迟和可恢复性。

3. 单机能扛很多连接,就不需要网关层

不对。连接承载、协议处理、限流、TLS、观测和业务逻辑最好分层。

参考资料

  • Dan Kegel, The C10K Problem
  • Linux epoll / Windows IOCP 相关资料
  • 各类长连接网关与 MMO 接入层实践资料
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu