原创

Linux内核参数调优之TCP

温馨提示:
本文最后更新于 2025年02月04日,已超过 74 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

 

/etc/sysctl.conf 文件用于配置 Linux 内核参数。通过修改此文件,可以永久性地调整内核行为,以优化系统性能、增强安全性或满足特定的应用需求。修改完成后,执行 sysctl -p 命令使更改生效。

一. TCP 三次握手

TCP三次握手过程是建立TCP连接的关键步骤,确保双方都准备好进行数据传输。下面是详细的过程

第一次握手

  • 客户端发送一个SYN(同步)包,表示请求建立连接。
  • 状态变化
    • 客户端状态从 CLOSED 变为 SYN_SENT

第二次握手

  • 服务器收到SYN包后,回复一个SYN-ACK包,表示同意建立连接,并确认收到客户端的SYN。
  • 状态变化
    • 服务器状态从 CLOSED 变为 SYN_RECEIVED
    • 客户端状态仍为 SYN_SENT

第三次握手

  • 客户端收到SYN-ACK包后,发送一个ACK(确认)包给服务器,确认收到服务器的SYN-ACK。
  • 状态变化
    • 客户端状态从 SYN_SENT 变为 ESTABLISHED,客户端的连接创建成功。
    • 服务器收到ACK包后,状态从 SYN_RECEIVED 变为 ESTABLISHED,服务器端的连接创建成功。

1.1 客户端优化

在 TCP 三次握手中,客户端作为主动发起连接方,首先发送一个 SYN 包,进入 SYN_SEND 状态。客户端会等待服务端回复的 ACK 报文。通常情况下,服务端会在几毫秒内返回 SYN+ACK。如果服务端未在指定时间内返回 SYN+ACK,客户端会根据 tcp_syn_retries 参数重新发送 SYN 包,默认重试次数为 5 次。

重传的超时机制如下:

  • 第一次超时重传:1 秒
  • 第二次超时重传:2 秒
  • 第三次超时重传:4 秒
  • 第四次超时重传:8 秒
  • 第五次超时重传:16 秒

在第五次重传后,客户端会等待 32 秒。如果服务端仍未回应 ACK,客户端将终止第三次握手,导致总耗时为 63 秒。

根据网络的稳定性和服务器的繁忙程度,可以调整 SYN 的重传次数,以优化客户端的三次握手时间。例如,在内网通信中,可以降低 SYN 重传次数,以便更快地将超时情况暴露给应用程序。

1.2 服务端优化

半连接队列

当服务端收到 SYN 后,会立即回应 SYN+ACK,此时服务端状态为 SYN_RECV。连接将被放入半连接队列中。如果半连接队列已满,连接将被丢弃。

可以通过以下命令查看因半连接队列已满导致的连接失败次数:

netstat -s | grep "SYNs to LISTEN"

调整 SYN 半连接队列大小的参数如下:

  • tcp_max_syn_backlog 的默认值为 128,建议在高并发环境下增加到 1024 或更高。
  • somaxconn 的默认值为 128,建议在高并发场景下增加至 4096 或更大。

设置较小的 tcp_max_syn_backlog 值可以防止服务器在面临 SYN 洪水攻击时资源被迅速耗尽,而较大的 somaxconn 值则可以确保在正常情况下服务器能够处理更多的连接请求。

net.ipv4.tcp_max_syn_backlog = 1024
net.core.somaxconn = 4096

对于 Nginx 和 Spring Boot 的 backlog 设置,分别如下:

Nginx 配置示例

server {
    listen 80 backlog=4096;
}

Spring Boot 配置示例

server:
  tomcat:
    accept-count: 4096

SYN攻击防护

在面对 SYN 攻击时,可以启用 SYN Cookies 功能,以在不使用半连接队列的情况下建立连接。

net.ipv4.tcp_syncookies = 1

SYN Cookies 的值有:

  • 0 - 禁用 SYN Cookies
  • 1 - 启用 SYN Cookies,仅在 SYN backlog 队列溢出时使用(默认值)
  • 2 - 强制启用 SYN Cookies

accept 队列

当客户端收到服务端发来的 SYN+ACK 时,会发送 ACK 给服务端,连接状态变为 ESTABLISHED。此时,内核会将连接从半连接队列中删除,并创建完全连接,添加到 accept 队列中,等待进程调用 accept 函数。如果 accept 队列满了,服务端将丢弃连接。可以通过 tcp_abort_on_overflow 参数调整 accept 队列的行为,默认值为 0,这样可以更好地应对突发流量。设置为 1 时,服务端将发送 RST 包给客户端,表示丢弃连接。

net.ipv4.tcp_abort_on_overflow = 0

调整 accept 队列长度

accept 队列的长度由 somaxconnbacklog 之间的最小值决定。使用以下命令查看 accept 队列长度:

ss -ltn

Recv-Q 表示当前 accept 队列大小,Send-Q 表示 accept 队列的最大长度。可以使用以下命令查看 accept 队列溢出的次数:

netstat -s | grep overflowed

SYN+ACK 重发机制

如果服务端未收到 ACK,将重发 SYN+ACK 报文,重发次数由 tcp_synack_retries 参数控制,默认值为 5 次。优化逻辑如下:

  • 网络繁忙或不稳定时,调大 tcp_synack_retries 参数。
  • 网络稳定时,调小 tcp_synack_retries 参数。
net.ipv4.tcp_synack_retries = 5

二. TCP 四次挥手

TCP 四次挥手是 TCP 连接终止的过程,确保安全关闭连接。以下是详细流程:

第一次挥手

  • 客户端发送一个FIN(结束)包,表示客户端没有数据要发送了。
  • 状态变化
    • 客户端状态从 ESTABLISHED 变为 FIN_WAIT_1

第二次挥手

  • 服务器收到FIN包后,回复一个ACK包,确认收到客户端的FIN。
  • 状态变化
    • 服务器状态从 ESTABLISHED 变为 CLOSE_WAIT,表示服务器端已准备好关闭连接,但可能还有数据需要发送。
    • 客户端状态从 FIN_WAIT_1 变为 FIN_WAIT_2,等待服务器端发送 FIN 报文。

第三次挥手

  • 服务器准备关闭连接,发送一个FIN包给客户端,表示服务器端也没有数据要发送了。
  • 状态变化
    • 服务器状态从 CLOSE_WAIT 变为 LAST_ACK
    • 客户端状态仍为 FIN_WAIT_2

第四次挥手

  • 客户端收到服务器的FIN包后,发送一个ACK包,确认收到服务器的FIN。
  • 状态变化
    • 客户端状态从 FIN_WAIT_2 变为 TIME_WAIT(通常保持2MSL的时间),等待一段时间以确保服务器端收到最后的 ACK 报文。
    • 服务端收到客户端的 ACK 报文后,进入 CLOSED 状态,表示连接已关闭。
    • 最后,客户端在TIME_WAIT状态结束后,变为 CLOSED状态。

2.1 主动方优化

FIN_WAIT_1 状态优化

FIN_WAIT_1 状态,如果迟迟收不到被动方的 ACK,内核会定时重发 FIN 报文,重发次数由 tcp_orphan_retries 参数决定,默认值为 0。建议适当降低此值,以快速关闭连接。

net.ipv4.tcp_orphan_retries = 3

如果攻击者下载大文件时,将接收窗口设置为 0,可能导致连接一直处于 FIN_WAIT_1 状态。此时可以通过 tcp_max_orphans 参数限制连接数量,默认值为1024,超过该参数时直接发送 RST 报文强制关闭。

net.ipv4.tcp_max_orphans = 2048

FIN_WAIT_2 状态下,可以通过 tcp_fin_timeout 参数设置超时时间,默认值为 60 秒。对于高并发服务器,可以适当减少此值(例如设置为 30 秒),以更快释放连接资源。

net.ipv4.tcp_fin_timeout = 30

2.2 被动方优化

CLOSE_WAIT 状态,调用 close 函数后,内核会发送 FIN 报文关闭发送通道,进入 LAST_ACK 状态。如果迟迟收不到 ACK,内核会重发 FIN 报文,重发次数由tcp_orphan_retries参数控制。

net.ipv4.tcp_orphan_retries = 3

三. TCP连接

3.1 保活机制

TCP 保活机制用于检测长时间未活动的连接。通过调整以下参数,可以更快地识别失效连接,特别是在不稳定的网络环境中:

  • tcp_keepalive_time:在没有数据传输的情况下,等待多长时间后开始发送 Keepalive 探测包(单位:秒),默认值为7200 秒。
  • tcp_keepalive_intvl:设置 Keepalive 探测包之间的时间间隔(单位:秒),默认值是75 秒。
  • tcp_keepalive_probes:在判定连接失效之前,最大发送的 Keepalive 探测包数量,默认值是9。

建议配置如下:

net.ipv4.tcp_keepalive_time = 300      # 5分钟
net.ipv4.tcp_keepalive_intvl = 60      # 每60秒重试一次
net.ipv4.tcp_keepalive_probes = 5      # 尝试5次

3.2 重试次数

TCP 使用确认(ACK)和超时重传机制来处理数据丢失。可以通过以下参数配置重试次数:

  • tcp_retries1:控制在 TCP 连接的第一次重传失败后,内核尝试的重传次数(默认值通常为 3 次)。
  • tcp_retries2:控制在 TCP 连接关闭状态下,内核尝试的重传次数(默认值通常为 15 次)。

在高延迟或不稳定的网络环境中配置如下:

net.ipv4.tcp_retries1 = 5
net.ipv4.tcp_retries2 = 20

3.3 缓冲区优化

优化 TCP 接收(tcp_rmem)和发送(tcp_wmem)缓冲区大小对性能有显著影响。根据不同的网络环境和系统配置,建议的配置如下:

  • 在高带宽环境中:
net.ipv4.tcp_rmem = 4096 87380 16777216  # 最小4KB,默认87KB,最大16MB
net.ipv4.tcp_wmem = 4096 16384 16777216  # 最小4KB,默认16KB,最大16MB
  • 在网络不稳定的情况下,应谨慎调整,以避免过高的重传率和网络拥塞:
net.ipv4.tcp_rmem = 4096 32768 4194304  # 最小4KB,默认32KB,最大4MB
net.ipv4.tcp_wmem = 4096 16384 4194304  # 最小4KB,默认16KB,最大4MB
  • 当服务器内存资源有限时,避免 TCP 缓冲区消耗过多内存:
net.ipv4.tcp_rmem = 4096 16384 1048576  # 最小4KB,默认16KB,最大1MB
net.ipv4.tcp_wmem = 4096 16384 1048576  # 最小4KB,默认16KB,最大1MB
正文到此结束