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_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é à 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é.
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
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.
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:
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)
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.
TIME_WAIT
voit le jour.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.
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.