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

39

J'exécute un site plutôt occupé et pendant les heures de pointe, je vois plus de 10 000 connexions ouvertes sur 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 l' TIME_WAITétat.

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

L'abaissement de cette valeur est-il sécurisé?

Aucune de mes requêtes 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 mysql_pconnectau lieu de mysql_connect, mais je n'ai lu que des histoires d'horreur à ce sujet, alors je pense que je vais rester à l'écart de cela.

Mr.Boon
la source
3
Il y a une différence entre les requêtes et les connexions. Vous devez au moins vous assurer que le logiciel de votre site Web ne s'interrompra pas si wait_timeoutune connexion plus courte provoque la fermeture d'une connexion alors que le logiciel s'attend à ce qu'elle reste ouverte.
John Gardeniers

Réponses:

74

Réduire la valeur est assez trivial sans un redémarrage de 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 à la base de données après ce délai expireront dans 30 secondes

ATTENTION

Assurez-vous d'utiliser explicitement mysql_close. Je ne fais pas confiance à Apache comme le font la plupart des développeurs. Sinon, il existe parfois une situation de concurrence critique dans laquelle Apache ferme une connexion à une base de données mais n'informe pas mysqld et ce dernier maintient cette connexion ouverte jusqu'à l'expiration du délai imparti. Pire encore, il est possible que vous voyiez plus souvent TIME_WAIT. Choisissez judicieusement vos valeurs de délai d'attente.

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

CAVEAT

Après avoir appliqué mes suggestions postées, créez un script appelé /root/show_mysql_netstat.shavec 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 ceci, vous devriez voir quelque chose comme ça:

[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 toujours beaucoup de mysql TIME_WAITspour un serveur Web donné, voici deux étapes à suivre:

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_WAIT 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 que TIME_WAIT expire en 1 seconde.

Donner un crédit lorsqu'un crédit est dû ...

RolandoMySQLDBA
la source
1
Près de 2k vues pour cela et seulement 2 votes en plus (y compris le mien, donc 1), wtf?! C'est une excellente réponse. Désolé, je ne peux donner qu'un vote!
Jwbensley
J'ai essayé cette technique et j'avais beaucoup de connexions CLOSE_WAIT (2622) mais pas de connexions TIME_WAIT. Comment dois-je interpréter ce résultat?
robguinness
4

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 ou plusieurs hôtes se soient retrouvés dans une liste de blocage. Vous pouvez effacer ceci en exécutant:

mysqladmin flush-hosts

Pour obtenir une liste du nombre de connexions que vous avez par IP, procédez comme suit:

 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 rencontre des difficultés pour se connecter et telnet au port 3306. Il affichera un message contenant 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.
utilisateur2566717
la source
1

Si vous avez beaucoup de connexions TIME_WAIT sur 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é permanente sur votre serveur de base de données, à l'aide de l'extension MySQLi.

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

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

Garreth McDaid
la source