Skip to content

网络容量、并发与性能

“一台服务器能承担多少并发”没有脱离环境的固定答案。连接数、每秒新建连接、请求吞吐、消息扇出和网络带宽是不同容量维度,必须分别建模。

连接为什么不受服务端端口数限制

TCP 连接由四元组唯一标识:

text
source IP + source port + destination IP + destination port

服务端监听 443 端口时,不同客户端地址和临时端口形成不同四元组,因此一个监听端口可以承载大量连接。

客户端用同一源 IP 连接同一目标时,更容易先耗尽临时端口。Linux 的可用范围由 ip_local_port_range 决定,还要扣除保留端口、既有占用和生命周期冲突。

bash
sysctl net.ipv4.ip_local_port_range
sysctl net.ipv4.ip_local_reserved_ports

增加客户端源 IP 或连接不同目标可以扩大四元组空间。连接池复用通常比持续创建短连接更有效。

文件描述符

Unix 中每个 Socket 通常占用一个文件描述符。容量要同时检查:

bash
ulimit -Sn
ulimit -Hn
sysctl fs.file-max
cat /proc/sys/fs/file-nr

Shell、systemd 与容器运行时可能配置不同上限。只提高 ulimit -n 不会自动增加内存、端口、连接跟踪和应用处理能力。

每连接内存

一条连接可能包含:

  • 内核 Socket 与 TCP 控制块。
  • 发送、接收和重传队列。
  • TLS 会话与加密缓冲。
  • 应用 Session、解析器、定时器和消息队列。
  • 分配器元数据与内存碎片。

容量估算应使用测量值:

text
memory ≈ connections × average bytes per connection + shared overhead

空闲连接、活跃连接和慢客户端的内存成本差异很大。不能用一个固定“每连接 64KB”覆盖所有工作负载。

bash
cat /proc/net/sockstat
ss -m
slabtop -o

三个不同指标

指标主要成本常见瓶颈
并发连接数状态、fd、内存、心跳fd、Socket 内存、conntrack
每秒新建连接SYN、对象分配、TLSCPU、队列、证书运算
请求或消息吞吐解析、业务、复制、下游CPU、线程池、数据库、网卡

百万空闲连接不代表能每秒建立百万连接,也不代表每条连接都能持续高吞吐。

带宽、包率与消息扇出

基础带宽模型:

text
outbound throughput
≈ active connections × messages per second × bytes per message × fan-out

还要加上 Ethernet、IP、TCP/UDP、TLS 和应用 Header。小消息场景可能先受每秒包数与系统调用影响,大消息场景更容易受网卡带宽和内存复制影响。

一次消息广播给十万连接,不能只按入口消息速率估算;真正出站负载要乘以扇出,并考虑序列化是否能够共享。

慢消费者与背压

当生产速度超过网络或客户端消费速度,数据会堆积在:

text
业务队列 → 应用发送队列 → Socket 发送缓冲 → 网络 → 客户端

每条连接必须有队列上限,并明确超限策略:

  • 丢弃已经过期的旧状态。
  • 合并同一对象的多次更新。
  • 暂停上游生产。
  • 降低订阅频率或消息精度。
  • 关闭长期无法追上的连接。

无限队列只是把背压变成内存故障。

中间设备容量

端到端容量由链路中最小上限决定:

text
客户端端口池
→ NAT 映射
→ 防火墙 conntrack
→ 负载均衡
→ 代理连接池
→ 服务器 Socket
→ 应用与下游

只压测服务器环回地址无法验证真实生产链路。NAT、云负载均衡和防火墙都有并发连接、每秒新建、超时与端口限制。

代理与连接池

反向代理接收客户端连接后,通常复用另一组上游连接。客户端有一万连接,不代表每个后端也需要一万连接。

HTTP/1.1 上游连接通常限制同时在途请求;HTTP/2 可以在一条连接上并发多个 Stream。连接池过小会排队,过大则可能压垮后端或制造端口压力。

应同时观察:

  • 活跃与空闲上游连接。
  • 等待连接池的请求数。
  • 每连接并发 Stream。
  • 建连、TLS、首字节与总耗时。
  • 重试次数和实际 Attempt 数。

DNS、CDN 与缓存容量

CDN 通过 Cache Key、TTL 和验证请求减少回源。错误的 Key 可能串内容,Key 过细则命中率过低。

缓存容量不能只看命中率,还要看:

  • 热点对象是否在失效瞬间引发回源洪峰。
  • 大对象是否驱逐大量小对象。
  • Vary、Cookie 和 Query 是否造成碎片化。
  • 过期对象能否在源站异常时提供 Stale 响应。

可复现压测模型

压测报告至少记录:

类别必要参数
环境CPU、内存、网卡、内核、容器限制
连接总数、每秒新建、TLS、空闲比例
消息大小、频率、方向、扇出、压缩
网络RTT、带宽、丢包、抖动、MTU
应用工作线程、队列、下游依赖
结果P50/P95/P99、错误率、资源和失败点

测试应逐步增加负载,使用尾延迟和错误率作为停止条件,并保留安全余量。只报告“成功建立多少连接”无法用于生产容量规划。

bash
ss -s
ss -ti
sar -n DEV,TCP,ETCP 1
pidstat -t -p PID 1
perf top -p PID

容量异常最终仍要回到证据链。下一篇 网络排障方法与案例 给出从客户端到服务端逐层收敛的流程。

别急,先让缓存热一下。