最近维护的业务量与日俱增,服务器不断出现各种问题。今天遇到了在开启 MySQL pconnect 情况下 TCP CLOSE_WAIT 连接状态激增的情况。CLOSE_WAIT 高达 8000 左右。

先来看看 TCP 协议是如何关闭一个连接的:

STEP 1: Client –FIN–> Server

STEP 2: Client <--ACK-- Server
此时 Client 处于FIN_WAIT_2 状态;而 Server 处于 CLOSE_WAIT 状态。

STEP 3: Client <--FIN-- Server
此时 Server 发送 FIN 给 Client,Server 置为 LAST_ACK 状态。

STEP 4: Client --ACK--> Server
Client 回应 ACK ,此时 Server 真正置为 CLOSED 状态。

Server 处于 CLOSE_WAIT 状态,而不是 LAST_ACK 状态,说明还没有发 FIN 给 Client,那么可能是在关闭连接之前还有许多数据要发送或者其他事要做,导致没有发这个 FIN packet。

默认情况下,一个 CLOSE_WAIT 会维持至少 2 个小时 (7200s) 的时间。通过修改一下 TCP 参数,来缩短这个时间:修改tcp_keepalive_* 系列参数有助于解决这个问题。

减少 CLOSE_WAIT:

net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_intvl = 2

减少 TIME_WAIT:

net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 1024    65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1

说明:

net.ipv4.tcp_syncookies = 1
表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN***,默认为0,表示关闭;

net.ipv4.tcp_tw_reuse = 1
表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle = 1
表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout = 30
表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。

net.ipv4.tcp_keepalive_time = 1200
表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。

net.ipv4.ip_local_port_range = 1024    65000
表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。

net.ipv4.tcp_max_syn_backlog = 8192
表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

net.ipv4.tcp_max_tw_buckets = 5000
表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。

net.ipv4.route.gc_timeout = 100
路由缓存刷新频率, 当一个路由失败后多长时间跳到另一个默认是300

net.ipv4.tcp_syn_retries = 1
对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃。不应该大于255,默认值是5,对应于180秒左右。

连接状态统计:

netstat-n|awk'/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'






source:http://www.inanu.net/post/328.html