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

39

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

Безопасно ли снижение этого значения?

Ни один из моих запросов обычно занимает больше секунды. Поэтому кажется глупым держать соединение открытым в течение 480 минут.

Я также слышал об использовании mysql_pconnectвместо mysql_connect, но я читал только ужасные истории об этом, поэтому я думаю, что буду держаться подальше от этого.

Mr.Boon
источник
3
Есть разница между запросами и соединениями. Вы должны по крайней мере убедиться, что программное обеспечение вашего веб-сайта не сломается, если более короткое время wait_timeoutприведет к закрытию соединения, когда оно ожидает, что оно останется открытым.
Джон Гарденер

Ответы:

74

Понижение значения довольно тривиально без перезапуска 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 ПО ВОСТОЧНОМУ ВРЕМЕНИ

ПРЕДОСТЕРЕЖЕНИЕ

После применения моих опубликованных предложений создайте сценарий /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для любого данного веб-сервера, вот два шага эскалации:

ESCALATION # 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)

ESCALATION # 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_WAIT через 1 секунду.

Чтобы дать кредит, где кредит должен ...

RolandoMySQLDBA
источник
1
Почти 2 000 просмотров за это и только 2 за голоса (включая мое, так что 1), WTF ?! Это отличный ответ. Извините, я могу отдать только один голос!
Jwbensley
Я попробовал эту технику, и у меня было много соединений CLOSE_WAIT (2622), но не было соединений TIME_WAIT. Как я должен интерпретировать этот результат?
Робинесс
4

Если вы получаете много подключений 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.
user2566717
источник
1

Если у вас много соединений TIME_WAIT с вашим сервером MySQL, это означает, что ваш код выполняет множество запросов к вашей БД и открывает / закрывает соединение для каждого запроса.

В этом случае вы должны использовать постоянное подключение к вашему серверу БД, используя расширение MySQLi.

http://php.net/manual/en/mysqli.persistconns.php

Если вы не можете использовать MySQLi, вы должны вместо этого использовать параметр thread_cache_size в вашей конфигурации MySQL.

Гаррет МакДейд
источник