1596 字
8 分钟
盘牛客面经-阿里后端一面网络

1. 客户端端口号如何确定?#

动态端口分配机制(Ephemeral Port)

客户端发起连接时:
1. 操作系统从临时端口范围随机选择未使用的端口
2. Linux: /proc/sys/net/ipv4/ip_local_port_range (默认32768-60999)
3. Windows: 49152-65535 (IANA标准)
4. macOS: 49152-65535
分配策略:
- 随机算法 + 避免冲突检测
- 端口被占用则继续尝试下一个
- 端口复用需设置 SO_REUSEADDR/SO_REUSEPORT

2. 服务端什么资源消耗最快?#

资源瓶颈优先级

  1. 文件描述符 (FD) - 最容易耗尽

    • 每个 TCP 连接消耗 1 个 FD
    • 默认限制:ulimit -n 通常 1024
    • 需调整:/etc/security/limits.conf
  2. 内存

    • 每个连接约消耗 4-10KB 内核内存(接收/发送缓冲区)
    • socket 缓冲区: net.ipv4.tcp_rmem / tcp_wmem
  3. 端口号(反向连接场景)

    • 作为客户端时受临时端口范围限制
  4. CPU(通常不是瓶颈)


3. 一个端口可以建立多少 TCP 连接?#

理论上无限制! 关键是理解四元组唯一性:

TCP连接由四元组唯一标识:
(源IP, 源端口, 目标IP, 目标端口)
服务端场景(监听80端口):
- 不同客户端IP → 不同连接
- 相同客户端IP的不同源端口 → 不同连接
示例:
服务器 192.168.1.100:80 可以同时建立:
- 客户端A (10.0.0.1:50000) → 连接1
- 客户端A (10.0.0.1:50001) → 连接2
- 客户端B (10.0.0.2:50000) → 连接3
...
理论上限:
- 单个客户端IP → ~64K连接(受客户端临时端口限制)
- 多个客户端IP → 取决于服务器资源(FD、内存)

4. 一个 TCP 连接供多少 HTTP 连接使用?#

取决于 HTTP 版本

版本连接复用机制
HTTP/1.01 个 TCP = 1 个 HTTP 请求短连接,完成即关闭
HTTP/1.11 个 TCP = 串行多个 HTTP 请求Keep-Alive 持久连接,管道化
HTTP/21 个 TCP = 并行无限个 HTTP 请求多路复用(Stream 机制)
HTTP/3基于 UDP (QUIC)连接迁移
HTTP/1.1 示例:
TCP连接保持打开 → 发送请求1 → 等待响应1 → 发送请求2 → ...
HTTP/2 示例:
TCP连接 → 同时发送请求1、2、3(不同Stream ID) → 响应乱序返回

5. 服务器可以支撑多少 TCP 连接?#

实际限制因素

Terminal window
# 1. 文件描述符限制(最常见瓶颈)
ulimit -n # 查看当前限制
# 修改 /etc/security/limits.conf:
* soft nofile 1000000
* hard nofile 1000000
# 2. 内存限制
假设每连接10KB内存:
100万连接 10GB内存
# 3. 内核参数调优
sysctl -w net.core.somaxconn=65535 # 监听队列
sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # SYN队列
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
# 4. 端口号限制(仅作为客户端时)
反向连接场景:~64K连接/目标IP

C10M 问题(千万级并发)

  • 需要内核旁路技术(DPDK、XDP)
  • 用户态协议栈

6. 客户端可以支撑多少 TCP 连接?#

主要限制

  1. 临时端口耗尽

    单目标IP+端口:
    最多 ~64K 连接(ip_local_port_range范围)
    解决方案:
    - 多目标IP/端口
    - 绑定多个本地IP
    - 端口复用 (SO_REUSEADDR)
  2. 文件描述符(同服务端)

  3. 内存(同服务端)


7. TCP 连接后一端 KILL 掉进程会发生什么?#

场景 A:正常 KILL(SIGTERM)#

1. 进程捕获信号
2. 关闭socket → 发送FIN包
3. 四次挥手正常进行
4. 对端收到FIN,连接正常关闭

场景 B:强制 KILL(SIGKILL)#

1. 进程立即终止,未主动关闭socket
2. 操作系统代为处理:
- 关闭所有FD → 自动发送FIN
3. 对端仍能正常收到FIN

场景 C:断电/断网#

断电(无法发送任何包):
1. 对端TCP栈继续保持连接
2. 发送数据 → 超时重传(指数退避)
3. 达到重传上限 → 标记连接失效
4. 应用层 read() 返回错误
断网(网络中断):
- 同断电,依赖TCP KeepAlive或应用层心跳检测
KeepAlive参数:
net.ipv4.tcp_keepalive_time = 7200 # 2小时后发送探测
net.ipv4.tcp_keepalive_intvl = 75 # 探测间隔75秒
net.ipv4.tcp_keepalive_probes = 9 # 探测9次失败断开

场景 D:对端直接拔网线#

发送数据时会发现:
1. TCP超时重传
2. 12-15次重传失败(约15-30分钟)
3. 返回 ETIMEDOUT 错误
优化方案:
- 启用 TCP_USER_TIMEOUT
- 应用层心跳(推荐30-60秒)

8. TIME_WAIT 一定出现在客户端吗?#

错!TIME_WAIT 出现在主动关闭方

四次挥手流程:
主动方:FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
被动方:CLOSE_WAIT → LAST_ACK → CLOSED
TIME_WAIT持续时间:2MSL(通常60秒)
示例场景:
1. 客户端先关闭 → 客户端TIME_WAIT
2. 服务端先关闭 → 服务端TIME_WAIT(如HTTP/1.0短连接)
3. Nginx主动关闭长连接 → Nginx进入TIME_WAIT

为什么需要 TIME_WAIT

  1. 确保最后的 ACK 被对方收到(可能需要重传)
  2. 防止旧连接的延迟数据包干扰新连接

9. 高并发下如何解决 TIME_WAIT 过多?#

方法 1:内核参数调优#

Terminal window
# 允许TIME_WAIT套接字重用(作为客户端)
net.ipv4.tcp_tw_reuse = 1
# 快速回收TIME_WAIT(不推荐,可能导致问题)
# net.ipv4.tcp_tw_recycle = 1 # 新版内核已移除
# 缩短TIME_WAIT时间(需重新编译内核)
# 默认60秒,可改为15-30秒

方法 2:端口复用#

int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); // Linux 3.9+

方法 3:架构优化(最佳实践)#

1. 连接池复用
- 保持长连接,避免频繁创建/销毁
2. 让客户端主动关闭
- TIME_WAIT分散到客户端
- HTTP/1.1 Keep-Alive + Connection: close
3. 使用HTTP/2
- 多路复用,减少连接数
4. 负载均衡
- 多个服务端IP → 分散TIME_WAIT
- IPVS、LVS-NAT
5. 增加本地IP
- 每个IP独立的端口范围
- 虚拟网卡绑定多IP

方法 4:应用层设计#

# 连接池示例(Python)
import requests
from requests.adapters import HTTPAdapter
session = requests.Session()
session.mount('http://', HTTPAdapter(pool_connections=100, pool_maxsize=100))
# 复用连接,避免TIME_WAIT
for _ in range(10000):
session.get('http://api.example.com')

核心总结#

问题关键点
端口分配操作系统动态分配,范围可调
服务器瓶颈文件描述符 > 内存 > 端口
端口连接数理论无限(四元组唯一)
HTTP 复用HTTP/2 多路复用最优
连接上限FD 限制、内存、内核参数
进程异常OS 自动发 FIN,断电靠超时
TIME_WAIT主动关闭方,可通过架构规避

高并发优化金字塔

应用层:连接池、HTTP/2、长连接
架构层:负载均衡、多IP、CDN
内核层:参数调优、端口复用
硬件层:增加内存、网卡优化
盘牛客面经-阿里后端一面网络
https://mizuki.mysqil.com/posts/盘牛客面经/阿里后端一面网络/
作者
Laoli
发布于
2025-10-17
许可协议
CC BY-NC-SA 4.0
封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00