MySQL obniża wartość wait_timeout do niższej liczby otwartych połączeń

39

Prowadzę raczej zajętą ​​witrynę, aw godzinach szczytu widzę ponad 10.000 otwartych połączeń z serwerem bazy danych na moim serwerze internetowym po uruchomieniu polecenia netstat. 99% połączeń jest w TIME_WAITstanie.

Dowiedziałem się o tej zmiennej mysql: wait_timeout http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_wait_timeout dzisiaj. Mój jest nadal ustawiony na domyślny 28.800 sekund.

Czy obniżenie tej wartości jest bezpieczne?

Żadne z moich zapytań zwykle zajmuje sekundę. Więc głupie wydaje się utrzymywanie połączenia przez 480 minut.

Słyszałem też o używaniu mysql_pconnectzamiast mysql_connect, ale czytałem o tym tylko horrory, więc myślę, że trzymam się od tego z daleka.

Mr.Boon
źródło
3
Istnieje różnica między zapytaniami a połączeniami. Musisz przynajmniej upewnić się, że oprogramowanie Twojej witryny nie ulegnie zerwaniu, jeśli krótsza wait_timeoutspowoduje zamknięcie połączenia, gdy oprogramowanie spodziewa się, że pozostanie otwarte.
John Gardeniers

Odpowiedzi:

74

Obniżenie wartości jest dość trywialne bez ponownego uruchomienia mysql

Powiedzmy, że chcesz skrócić limity czasu do 30 sekund

Najpierw dodaj to do my.cnf

[mysqld]
interactive_timeout=30
wait_timeout=30

Następnie możesz zrobić coś takiego

mysql -uroot -ppassword -e"SET GLOBAL wait_timeout=30; SET GLOBAL interactive_timeout=30"

Wszystkie połączenia DB po tym czasie przekroczą limit czasu za 30 sekund

OSTRZEŻENIE

Upewnij się, że używasz jawnie użyj mysql_close. Nie ufam Apache, jak większość programistów. Jeśli nie, czasami zdarzają się warunki wyścigu, w których Apache zamyka połączenie DB, ale nie informuje mysqld i mysqld utrzymuje połączenie otwarte, dopóki nie przekroczy limitu czasu. Co gorsza, możesz zobaczyć TIME_WAIT częściej. Wybierz mądrze wartości limitu czasu.

AKTUALIZACJA 2012-11-12 10:10 EDT

CAVEAT

Po zastosowaniu moich opublikowanych sugestii utwórz skrypt /root/show_mysql_netstat.sho następujących liniach:

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/'

Po uruchomieniu tego powinieneś zobaczyć coś takiego:

[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

Jeśli nadal widzisz dużo mysql TIME_WAITsdla dowolnego serwera WWW, wykonaj dwa kroki eskalacji:

ESKALACJA # 1

Zaloguj się do szkodliwego serwera WWW i uruchom ponownie apache w następujący sposób:

service httpd stop
sleep 30
service httpd start

W razie potrzeby zrób to na wszystkich serwerach internetowych

service httpd stop (on all web servers)
service mysql stop
sleep 120
service mysql start
service httpd start (on all web servers)

ESKALACJA # 2

Możesz zmusić system operacyjny do zabicia TIME_WAIT dla mysql lub dowolnej innej aplikacji za pomocą:

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

Spowoduje to przekroczenie limitu czasu TIME_WAIT za 1 sekundę.

Udzielanie kredytu tam, gdzie jest on należny ...

RolandoMySQLDBA
źródło
1
Prawie 2k wyświetleń za to i tylko 2 więcej głosów (w tym moje, więc 1), wtf ?! To świetna odpowiedź. Przepraszam, mogę oddać tylko 1 głos!
jwbensley,
Wypróbowałem tę technikę i miałem wiele połączeń CLOSE_WAIT (2622), ale nie miałem połączeń TIME_WAIT. Jak mam interpretować ten wynik?
robguinness
4

Jeśli otrzymujesz wiele połączeń TIME_WAIT na serwerze MySQL, oznacza to, że serwer MySQL zamyka połączenie. Najbardziej prawdopodobnym przypadkiem w tym przypadku byłoby umieszczenie hosta lub kilku hostów na liście bloków. Możesz to usunąć, uruchamiając:

mysqladmin flush-hosts

Aby uzyskać listę liczby połączeń, które masz dla każdego adresu IP:

 netstat -nat | awk {'print $5'} | cut -d ":" -f1 | sort | uniq -c | sort -n

Możesz również potwierdzić, że tak się dzieje, przechodząc do jednego z klientów, który ma problemy z połączeniem i telnetem z portem 3306. Wyświetli się komunikat zawierający coś takiego:

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.
użytkownik2566717
źródło
1

Jeśli masz wiele połączeń TIME_WAIT z serwerem MySQL, oznacza to, że kod uruchamia wiele zapytań w bazie danych DB i otwiera / zamyka połączenie dla każdego zapytania.

W takim przypadku należy użyć trwałej łączności z serwerem DB, używając rozszerzenia MySQLi.

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

Jeśli nie możesz używać MySQLi, powinieneś zamiast tego użyć parametru thread_cache_size w konfiguracji MySQL.

Garreth McDaid
źródło