Linux内核参数调优之TCP
/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 Cookies1
- 启用 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 队列的长度由 somaxconn
和 backlog
之间的最小值决定。使用以下命令查看 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
- 本文标签: Linux内核调优
- 本文链接: https://lanzi.cyou/article/33
- 版权声明: 本文由咖啡豆原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权