web-dev-qa-db-fra.com

MySQL abaisse la valeur de wait_timeout pour réduire le nombre de connexions ouvertes

Je gère un site plutôt occupé et pendant les heures de visionnement, je vois plus de 10 000 connexions ouvertes à mon serveur de base de données sur mon serveur Web lors de l'exécution d'une commande netstat. 99% des connexions sont dans le TIME_WAIT Etat.

J'ai découvert cette variable mysql: wait_timeouthttp://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_wait_timeout aujourd'hui. Le mien est toujours réglé à 28,800 secondes par défaut.

La réduction de cette valeur est-elle sûre?

Aucune de mes requêtes ne prend généralement plus d'une seconde. Il semble donc idiot de garder une connexion ouverte pendant 480 minutes.

J'ai également entendu parler de l'utilisation de mysql_pconnect au lieu de mysql_connect, mais je n'ai lu que des histoires d'horreur à ce sujet, donc je pense que je vais m'en tenir éloigné.

40
Mr.Boon

Réduire la valeur est assez trivial sans redémarrage mysql

Disons que vous voulez réduire les délais d'attente à 30 secondes

Tout d'abord, ajoutez ceci à my.cnf

[mysqld]
interactive_timeout=30
wait_timeout=30

Ensuite, vous pouvez faire quelque chose comme ça

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

Toutes les connexions DB après ce délai expireront dans 30 secondes

ATTENTION

Assurez-vous d'utiliser explicitement mysql_close. Je ne fais pas confiance à Apache comme la plupart des développeurs. Sinon, parfois, il existe une condition de concurrence critique où Apache ferme une connexion DB mais n'informe pas mysqld et mysqld de maintenir cette connexion ouverte jusqu'à ce qu'elle expire. Pire encore, vous pouvez voir TIME_WAITs plus souvent. Choisissez judicieusement vos valeurs de timeout.

MISE À JOUR 2012-11-12 10:10 EDT

CAVEAT

Après avoir appliqué mes suggestions publiées, créez un script appelé /root/show_mysql_netstat.sh avec les lignes suivantes:

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

Lorsque vous exécutez cela, vous devriez voir quelque chose comme ceci:

[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

Si vous voyez encore beaucoup de mysql TIME_WAITs pour un serveur Web donné, voici deux étapes d'escalade:

ESCALATION # 1

Connectez-vous au serveur Web incriminé et redémarrez Apache comme suit:

service httpd stop
sleep 30
service httpd start

Si nécessaire, faites-le sur tous les serveurs Web

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

ESCALATION # 2

Vous pouvez forcer le système d'exploitation à tuer TIME_WAITs pour mysql ou toute autre application avec les éléments suivants:

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

Cela fera expirer TIME_WAITs en 1 seconde.

Donner du crédit là où le crédit est dû ...

75
RolandoMySQLDBA

Si vous obtenez beaucoup de connexions TIME_WAIT sur le serveur MySQL, cela signifie que le serveur MySQL ferme la connexion. Le cas le plus probable dans ce cas serait qu'un hôte ou plusieurs hôtes soient inscrits sur une liste de blocage. Vous pouvez effacer cela en exécutant:

mysqladmin flush-hosts

Pour obtenir une liste du nombre de connexions que vous avez par exécution IP:

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

Vous pouvez également confirmer que cela se produit en vous adressant à l'un de vos clients qui a des problèmes de connexion et de telnet au port 3306. Il affichera un message avec quelque chose comme:

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.
4
user2566717

Si vous avez beaucoup de connexions TIME_WAIT à votre serveur MySQL, cela signifie que votre code exécute de nombreuses requêtes sur votre base de données et ouvre/ferme une connexion pour chaque requête.

Dans ce cas, vous devez utiliser une connectivité persistante à votre serveur de base de données, en utilisant l'extension MySQLi.

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

Si vous ne pouvez pas utiliser MySQLi, vous devez plutôt utiliser le paramètre thread_cache_size dans votre configuration MySQL.

1
Garreth McDaid