Назад | Перейти на главную страницу

MySQL снижает значение wait_timeout для уменьшения количества открытых соединений

У меня довольно загруженный сайт, и в часы просмотра я вижу более 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. Выбирайте значения тайм-аута с умом.

ОБНОВЛЕНИЕ 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

Если вы все еще видите много mysql TIME_WAITs для любого заданного веб-сервера необходимо предпринять два шага эскалации:

ЭСКАЛАЦИЯ # 1

Войдите на проблемный веб-сервер и перезапустите 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)

ЭСКАЛАЦИЯ # 2

Вы можете заставить ОС убить 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 на сервере 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.