飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • IP协议

    • 认识 IP 协议与网络层定位
    • IPv4 编址体系与分类地址
    • CIDR 与子网划分实战
    • IPv6 编址体系
    • ARP 协议详解
    • NDP 协议详解
    • IGMP 与 MLD 组播侦听发现
    • VRRP 与网关冗余
    • IPv4 数据报首部解析
    • IPv6 数据报与扩展首部
    • IPsec 安全扩展
    • 分片、MTU 与路径发现
    • ICMP 与 Traceroute 原理
    • 路由基础与转发流水线
    • 动态路由协议
    • NAT 网络地址转换
    • DHCP 与自动配置
    • Wireshark 与命令行工具
    • IPv6 过渡技术
    • IP 协议栈排障与攻击防御
  • TCP协议

    • 认识 TCP 协议与传输层定位
    • TCP 报文段首部解析
    • 三次握手与连接建立
    • 四次挥手与连接释放
    • TCP 有限状态机
    • 序列号与确认机制
    • 超时重传与 RTO 计算
    • 滑动窗口与流量控制
    • 拥塞控制基础
    • 现代拥塞控制算法
    • TCP 选项与扩展
    • TCP 性能调优与内核参数
    • Nagle 算法与糊涂窗口综合征
    • TCP 定时器与 Keep-Alive 机制
    • TCP 安全与攻击防御
    • TCP 与上层/下层交互
    • TCP 综合实践与排障

TCP 性能调优与内核参数

高并发服务器的 TCP 挑战

Web 服务器处理 10 万并发连接时,TCP 层面临:

  • TIME_WAIT 堆积:主动关闭大量连接,端口耗尽
  • 半连接队列溢出:SYN Flood 或突发流量导致 SYN Queue 满
  • 全连接队列溢出:应用层处理慢,Accept Queue 满
  • 内存压力:每个连接占用内核 TCB、发送/接收缓冲区

TIME_WAIT 调优

问题

高并发短连接场景(如 REST API),服务端主动关闭后产生大量 TIME_WAIT:

ss -tan | grep TIME-WAIT | wc -l
# 可能达到数万甚至数十万

TIME_WAIT 持续 2MSL(Linux 默认 60 秒),同一 {目的IP:目的端口} 组合下会占用本地端口。

调优参数

# 允许复用 TIME_WAIT 连接(仅出站连接,安全)
sysctl net.ipv4.tcp_tw_reuse=1

# 缩短 TIME_WAIT 持续时间(秒)
sysctl net.ipv4.tcp_fin_timeout=30

# 注意:tcp_tw_recycle 在 NAT 环境有风险,Linux 4.12+ 已移除

根本解决方案:

  • HTTP Keep-Alive:复用 TCP 连接
  • 连接池:数据库/缓存客户端维护长连接
  • 让客户端主动关闭:服务端不进入 TIME_WAIT

SYN Flood 防护

半连接队列(SYN Queue)

服务端收到 SYN 后,连接进入 SYN_RCVD 状态,占用半连接队列。队列大小由 tcp_max_syn_backlog 控制。

全连接队列(Accept Queue)

三次握手完成后,连接进入 ESTABLISHED,等待应用层 accept()。队列大小由 min(somaxconn, backlog) 决定。

关键参数

# 半连接队列长度
sysctl net.ipv4.tcp_max_syn_backlog=65536

# 全连接队列长度(配合 listen() 的 backlog)
sysctl net.core.somaxconn=65535

# SYN Cookie 开启(SYN Flood 防护)
sysctl net.ipv4.tcp_syncookies=1

注意:listen(fd, backlog) 中的 backlog 是应用层传入的,实际队列大小 = min(somaxconn, backlog)。很多应用(如 Redis、Nginx)默认 backlog 较小,需同时调整应用配置。

缓冲区与内存调优

发送/接收缓冲区

# 全局缓冲区范围(字节)
sysctl net.ipv4.tcp_rmem="4096 87380 6291456"   # 读缓冲区: min default max
sysctl net.ipv4.tcp_wmem="4096 65536 6291456"   # 写缓冲区: min default max

# 自动调优(根据 RTT 和 BDP 动态调整)
sysctl net.ipv4.tcp_moderate_rcvbuf=1

缓冲区与 BDP 的关系:

最优缓冲区 = BDP = 带宽 × RTT

例如:带宽 1Gbps = 125MB/s, RTT = 100ms
BDP = 125MB/s × 0.1s = 12.5MB
缓冲区应 ≥ 12.5MB 才能充分利用带宽

其他关键内核参数

参数默认值建议值作用
tcp_timestamps11启用时间戳选项(RTT测量+PAWS)
tcp_window_scaling11启用窗口缩放
tcp_sack11启用选择性确认
tcp_ecn02启用 ECN(0=关闭, 1=开启, 2=被动)
tcp_fastopen13TFO 模式(1=客户端, 2=服务端, 3=双向)
tcp_retries2158放弃连接前的重传次数
tcp_slow_start_after_idle10空闲后是否重置 cwnd(建议 0)

诊断工具

# 查看连接统计
ss -s

# 查看详细连接信息(含拥塞窗口)
ss -ti

# 查看 TCP 内存使用
cat /proc/net/sockstat

# 查看内核参数
cat /proc/sys/net/ipv4/tcp_*

# 实时观察 cwnd 变化(需 root)
tcpdump -i eth0 -w capture.pcap
# 用 Wireshark 分析: Statistics → TCP Stream Graphs → Window Scaling

本篇小结

  • TIME_WAIT:用 Keep-Alive/连接池/客户端主动关闭解决,参数调优仅临时缓解
  • SYN Queue + Accept Queue:分别控制半连接和全连接,需同时调大
  • SYN Cookie:防止 SYN Flood,开启后无队列限制
  • 缓冲区:应 ≥ BDP(带宽×RTT),自动调优通常足够
  • 关键参数:timestamps、window_scaling、sack、ecn、fastopen
  • 诊断:ss -s / ss -ti / /proc/net/sockstat

动手实践

  1. 查看当前 TCP 连接统计:

    ss -s
    
  2. 查看某条连接的详细参数(含 cwnd、rtt、ssthresh):

    ss -ti | head -20
    
  3. 批量调整内核参数(测试环境):

    sudo sysctl -w net.ipv4.tcp_tw_reuse=1
    sudo sysctl -w net.ipv4.tcp_fin_timeout=30
    sudo sysctl -w net.core.somaxconn=65535
    sudo sysctl -w net.ipv4.tcp_max_syn_backlog=65536
    
  4. 思考:为什么 tcp_slow_start_after_idle 建议设为 0?如果空闲 10 秒后 cwnd 重置为 1,对长连接应用有什么影响?

上一页
TCP 选项与扩展
下一页
Nagle 算法与糊涂窗口综合征