У меня довольно загруженный сайт, и в часы просмотра я вижу более 10.000 открытых подключений к моему серверу базы данных на моем веб-сервере при запуске команды netstat. 99% подключений находятся в TIME_WAIT
штат.
Я узнал об этой переменной mysql: wait_timeout
http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_wait_timeout Cегодня. У меня по-прежнему установлено значение по умолчанию 28 800 секунд.
Безопасно ли снижать это значение?
Ни один из моих запросов обычно не занимает секунду. Так что держать соединение открытым 480 минут кажется глупым.
Я также слышал об использовании mysql_pconnect
вместо того mysql_connect
, но я не читал ничего, кроме ужасных историй об этом, так что я думаю, что буду держаться от этого подальше.
Понижение значения довольно тривиально без перезапуска 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. Выбирайте значения тайм-аута с умом.
После применения моих опубликованных предложений создайте скрипт под названием /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
Если вы все еще видите много mysql TIME_WAITs
для любого заданного веб-сервера необходимо предпринять два шага эскалации:
Войдите на проблемный веб-сервер и перезапустите apache следующим образом:
service httpd stop
sleep 30
service httpd start
При необходимости проделайте это со всеми веб-серверами.
service httpd stop (on all web servers)
service mysql stop
sleep 120
service mysql start
service httpd start (on all web servers)
Вы можете заставить ОС убить TIME_WAIT для mysql или любого другого приложения с помощью следующего:
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_WAITs через 1 секунду.
TIME_WAIT
появляется.Если вы получаете много соединений TIME_WAIT на сервере MySQL, это означает, что сервер 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.
Если у вас много соединений TIME_WAIT с вашим сервером MySQL, это означает, что ваш код выполняет множество запросов к вашей БД и открывает / закрывает соединение для каждого запроса.
В этом случае вы должны использовать постоянное соединение с вашим сервером БД, используя расширение MySQLi.
http://php.net/manual/en/mysqli.persistconns.php
Если вы не можете использовать MySQLi, вам следует вместо этого использовать параметр thread_cache_size в вашей конфигурации MySQL.