连接容量:一台服务器能连多少客户端
假设你在维护一个推送网关:手机 App 打开后和它建立一条 TCP 长连接,每 30 秒发一次心跳,订单状态一变,网关就把消息推下去。用户量涨了,有人问:这台机器最多能挂多少个 App?
常听到的回答是 65535,因为端口号是 16 位,最大就是 65535。这个数字离真实答案很远。一条连接从建立到长期保持,要依次通过好几道关卡,65535 只出现在第一道,而且卡的主要是发起连接的一方。
这个小系列跟着一条连接把这些关卡走一遍。读之前只需要知道 TCP 连接和端口是什么,不熟悉可以先看 TCP、UDP 与 Socket。读完后,遇到“连接数上不去”或“连接一多就出问题”,你应该能判断卡在哪一道,用哪条命令去确认,以及调高一个参数后瓶颈会移到哪里。
一条连接要过的五道关卡
这五道关卡是串联的。端口决定能不能区分出这条连接;文件描述符决定应用能不能拿到它;内存决定能同时存下多少条;CPU 和处理模型决定这些连接能不能被及时处理;内核队列决定新连接在握手阶段会不会被挡在门外。实际能承载的连接数,由最先被触碰的那一道决定。
所以“最多多少连接”没有一个固定数字。默认配置的机器,往往在一千条左右就被文件描述符卡住;把它放开以后,瓶颈才移到内存和 CPU,这时的上限取决于每条连接实际占多少内存、多久发一次心跳。
按症状找入口
如果你是带着具体问题来的,可以直接跳到对应的一篇:
| 你看到的现象 | 先读 |
|---|---|
客户端或反向代理报 Cannot assign requested address | 01 65535 卡住的是谁 |
服务端日志出现 Too many open files,连接只有一千左右 | 02 为什么一千多条就报 Too many open files |
| 连接数不算多,内存却涨得很快,甚至被 OOM | 03 一条连接到底占多少内存 |
| 连接一多延迟就升高,重启后大量客户端超时 | 04 连得上之后:心跳、重连风暴与事件模型 |
| 偶尔建连超时,CPU 和内存却都不高 | 05 握手完成还要排队:accept 队列 |
| 连接数没满,消息延迟越来越大 | 06 连接之外:吞吐、扇出与背压 |
第 04 篇会用到线程、事件循环和排队,这些概念不熟悉,可以先看 并发基础。第一次系统学习,按 01 到 06 的顺序读。每篇只回答一个问题,都带一个几分钟就能跑完的实验,先看现象,再讲原因,最后给出在真实服务器上的检查和调整方法。
准备实验环境
实验需要 Linux 内核,因为端口范围、文件描述符、Socket 内存和监听队列都是 Linux 的行为。最省事的方式是在 Docker 里跑,macOS 和 Windows 上装好 Docker Desktop 即可;直接用一台 Linux 虚拟机也可以。
新建一个空目录,放入下面的 Dockerfile。它在 Python 镜像里补上 ss 和 openssl 两个观察工具:
dockerfile
FROM public.ecr.aws/docker/library/python:3.13-slim
RUN apt-get update && apt-get install -y --no-install-recommends iproute2 openssl \
&& rm -rf /var/lib/apt/lists/*在这个目录里构建一次:
bash
docker build -t capacity-lab .构建完成后,docker image ls capacity-lab 能列出这个镜像。之后每篇的实验都是一个 Python 脚本,保存到同一个目录,用 docker run ... capacity-lab 运行。容器用完即删,实验里修改的内核参数只作用于容器自己的网络命名空间,不会影响宿主机。
文中给出的实验输出来自 2026 年 10 月的一次实际运行:Docker Desktop 的 Linux 7.0 内核,10 个虚拟 CPU,7.7 GiB 内存,Python 3.13。换一台机器,具体数字会有出入,但现象和数量级应该一致。
准备好以后,从第一道关卡开始:01 65535 卡住的是谁。
