MySQL diminuindo o valor wait_timeout para diminuir o número de conexões abertas

39

Eu administro um site bastante ocupado e, durante as horas de pico, vejo mais de 10.000 conexões abertas com meu servidor de banco de dados no meu servidor da Web quando um comando netstat é executado. 99% das conexões estão no TIME_WAITestado.

Aprendi sobre esta variável mysql: wait_timeout http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_wait_timeout hoje. O meu ainda está definido nos 28.800 segundos padrão.

A redução desse valor é segura?

Normalmente, minhas consultas não demoram mais de um segundo. Portanto, parece bobagem manter uma conexão aberta por 480 minutos.

Também ouvi falar sobre o uso em mysql_pconnectvez de mysql_connect, mas não tenho lido nada além de histórias de horror sobre isso, então acho que vou ficar longe disso.

Mr.Boon
fonte
3
Há uma diferença entre consultas e conexões. Você precisa pelo menos garantir que o software do site não seja interrompido se um menor wait_timeoutcausar o fechamento de uma conexão quando o software espera que ele permaneça aberto.
John Gardeniers

Respostas:

74

Reduzir o valor é bastante trivial sem uma reinicialização do mysql

Digamos que você queira reduzir o tempo limite para 30 segundos

Primeiro, adicione isso ao my.cnf

[mysqld]
interactive_timeout=30
wait_timeout=30

Então, você pode fazer algo assim

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

Todas as conexões de banco de dados após isso expirarão em 30 segundos

ATENÇÃO

Certifique-se de usar explicitamente o mysql_close. Não confio no Apache como a maioria dos desenvolvedores. Caso contrário, às vezes, há uma condição de corrida em que o Apache fecha uma conexão com o banco de dados, mas não informa ao mysqld e o mysqld mantém essa conexão aberta até o tempo limite. Pior ainda, você pode ver TIME_WAITs com mais frequência. Escolha seus valores de tempo limite com sabedoria.

UPDATE 2012-11-12 10:10 EDT

EMBARGO

Depois de aplicar minhas sugestões postadas, crie um script chamado /root/show_mysql_netstat.shcom as seguintes linhas:

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

Quando você executa isso, você deve ver algo assim:

[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

Se você ainda vir muito mysql TIME_WAITspara qualquer servidor web, seguem duas etapas de escalação a serem seguidas:

ESCALAÇÃO # 1

Efetue login no servidor da web ofensivo e reinicie o apache da seguinte maneira:

service httpd stop
sleep 30
service httpd start

Se necessário, faça isso com todos os servidores web

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

ESCALAÇÃO # 2

Você pode forçar o sistema operacional a eliminar TIME_WAITs para mysql ou qualquer outro aplicativo com o seguinte:

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

Isso fará com que TIME_WAITs atinja o tempo limite em 1 segundo.

Para dar crédito onde o crédito é devido ...

RolandoMySQLDBA
fonte
11
Quase 2k visualizações para isso e apenas 2 votos positivos (incluindo o meu, então 1), wtf ?! Esta é uma ótima resposta. Desculpe, só posso dar 1 voto!
jwbensley
Eu tentei essa técnica e tinha muitas conexões CLOSE_WAIT (2622), mas não conexões TIME_WAIT. Como devo interpretar esse resultado?
00009 Robbieness
4

Se você está recebendo muitas conexões TIME_WAIT no MySQL Server, isso significa que o servidor MySQL está fechando a conexão. O caso mais provável nesse caso seria que um host ou vários hosts entrassem em uma lista de bloqueios. Você pode limpar isso executando:

mysqladmin flush-hosts

Para obter uma lista do número de conexões que você tem por execução de IP:

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

Você também pode confirmar que isso está acontecendo, indo para um de seus clientes que está com problemas para conectar e telnet à porta 3306. Ele mostrará uma mensagem com algo como:

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
fonte
1

Se você tiver muitas conexões TIME_WAIT com o servidor MySQL, significa que o código está executando muitas consultas no seu banco de dados e abrindo / fechando uma conexão para cada consulta.

Nesse caso, você deve usar conectividade persistente ao seu servidor de banco de dados, usando a extensão MySQLi.

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

Se você não pode usar o MySQLi, deve usar o parâmetro thread_cache_size na sua configuração do MySQL.

Garreth McDaid
fonte