我运行一个相当繁忙的网站,在高峰时段,当我运行 netstat 命令时,我会看到我的网络服务器上有超过 10,000 个到数据库服务器的打开连接。99% 的连接处于该TIME_WAIT
状态。
我了解了这个mysql变量:wait_timeout
http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_wait_timeout今天。我的仍然设置为默认的 28.800 秒。
降低这个值是否安全?
我的查询通常都不会超过一秒钟。因此,让连接保持打开状态 480 分钟似乎很愚蠢。
我也听说过使用mysql_pconnect
而不是mysql_connect
,但是我读到的都是关于它的恐怖故事,所以我想我会远离它。
答案1
无需重启 mysql,降低该值非常简单
假设你想将超时时间缩短至 30 秒
首先,将其添加到 my.cnf
[mysqld]
interactive_timeout=30
wait_timeout=30
然后你可以做这样的事情
mysql -uroot -ppassword -e"SET GLOBAL wait_timeout=30; SET GLOBAL interactive_timeout=30"
此后的所有数据库连接将在 30 秒内超时
警告
确保明确使用 mysql_close。我不像大多数开发人员那样信任 Apache。如果不信任,有时就会出现竞争条件,Apache 关闭数据库连接但不通知 mysqld,mysqld 会保持该连接打开直到超时。更糟糕的是,您可能会更频繁地看到 TIME_WAIT。请明智地选择您的超时值。
更新时间:2012-11-12 10:10 EDT
警告
应用我发布的建议后,创建一个名为/root/show_mysql_netstat.sh
以下行的脚本:
netstat | grep mysql > /root/mysql_netstat.txt
cat /root/mysql_netstat.txt | awk '{print $5}' | sed 's/:/ /g' | awk '{print $2}' | sort -u > /root/mysql_netstat_iplist.txt
for IP in `cat /root/mysql_netstat_iplist.txt`
do
ESCOUNT=`cat /root/mysql_netstat.txt | grep ESTABLISHED | awk '{print $5}' | grep -c "${IP}"`
TWCOUNT=`cat /root/mysql_netstat.txt | grep TIME_WAIT | awk '{print $5}' | grep -c "${IP}"`
IPPAD=`echo "${IP}..................................." | cut -b -35`
(( ESCOUNT += 1000000 ))
(( TWCOUNT += 1000000 ))
ES=`echo ${ESCOUNT} | cut -b 3-`
TW=`echo ${TWCOUNT} | cut -b 3-`
echo ${IPPAD} : ESTABLISHED:${ES} TIME_WAIT:${TW}
done
echo ; echo
netstat -nat | awk '{print $6}' | sort | uniq -c | sort -n | sed 's/d)/d/'
当你运行这个程序时,你应该看到类似这样的内容:
[root@*** ~]# /root/ShowConnProfiles.sh
10.48.22.4......................... : ESTABLISHED:00002 TIME_WAIT:00008
10.48.22.8......................... : ESTABLISHED:00000 TIME_WAIT:00002
10.64.51.130....................... : ESTABLISHED:00001 TIME_WAIT:00000
10.64.51.133....................... : ESTABLISHED:00000 TIME_WAIT:00079
10.64.51.134....................... : ESTABLISHED:00002 TIME_WAIT:00001
10.64.51.17........................ : ESTABLISHED:00003 TIME_WAIT:01160
10.64.51.171....................... : ESTABLISHED:00002 TIME_WAIT:00000
10.64.51.174....................... : ESTABLISHED:00000 TIME_WAIT:00589
10.64.51.176....................... : ESTABLISHED:00001 TIME_WAIT:00570
1 established
1 Foreign
11 LISTEN
25 ESTABLISHED
1301 TIME_WAIT
如果您仍然看到任何给定的 Web 服务器上有很多 mysql TIME_WAITs
,请采取以下两个升级步骤:
升级 #1
登录到有问题的 Web 服务器并重新启动 apache,如下所示:
service httpd stop
sleep 30
service httpd start
如果有必要,对所有 Web 服务器执行此操作
service httpd stop (on all web servers)
service mysql stop
sleep 120
service mysql start
service httpd start (on all web servers)
升级 #2
您可以使用以下命令强制操作系统杀死 mysql 或任何其他应用程序的 TIME_WAIT:
SEC_TO_TIMEWAIT=1
echo ${SEC_TO_TIMEWAIT} > /proc/sys/net/ipv4/tcp_tw_recycle
echo ${SEC_TO_TIMEWAIT} > /proc/sys/net/ipv4/tcp_tw_reuse
这将使 TIME_WAIT 在 1 秒内超时。
给予应得赞扬的人赞扬...
- 我从这篇文章中得到了这个想法:如何强制关闭处于TIME_WAIT状态的套接字?
- 接受的答案用图形来表示某事物的
TIME_WAIT
诞生。 - 我喜欢的答案是我现在建议的答案。
答案2
如果 MySQL 服务器上有大量 TIME_WAIT 连接,则意味着 MySQL 服务器正在关闭连接。在这种情况下,最可能的情况是一台或多台主机被列入了阻止列表。您可以通过运行以下命令来清除此问题:
mysqladmin flush-hosts
要获取每个 IP 运行的连接数列表:
netstat -nat | awk {'print $5'} | cut -d ":" -f1 | sort | uniq -c | sort -n
您还可以通过访问出现连接问题的客户端之一并 telnet 到端口 3306 来确认是否发生了这种情况。它将显示类似以下内容的消息:
telnet mysqlserver 3306
Trying 192.168.1.102...
Connected to mysqlserver.
Escape character is '^]'.
sHost 'clienthost.local' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'Connection closed by foreign host.
答案3
如果您的 MySQL 服务器有大量 TIME_WAIT 连接,则意味着您的代码正在针对数据库运行大量查询,并且为每个查询打开/关闭一个连接。
在这种情况下,您应该使用 MySQLi 扩展与您的 DB 服务器建立持久连接。
http://php.net/manual/en/mysqli.persistconns.php
如果您不能使用 MySQLi,则应该使用 MySQL 配置中的 thread_cache_size 参数。