Estou procurando um script bash bem testado (ou solução alternativa) para fazer isso, a fim de evitar que max_connection se esgote. Eu sei que ele está combatendo os sintomas, mas realmente precisa de um script como uma solução de curto prazo.
Estou procurando um script bash bem testado (ou solução alternativa) para fazer isso, a fim de evitar que max_connection se esgote. Eu sei que ele está combatendo os sintomas, mas realmente precisa de um script como uma solução de curto prazo.
Respostas:
confira o comando pt-kill do kit de ferramentas percona .
e .. comece a monitorar seu sistema - munin , cactos com melhores modelos de cactos para mysql , qualquer coisa para que você tenha uma idéia do que está acontecendo. registrar consultas lentas do mysql também será uma boa idéia.
Se você possui o MySQL 5.1 onde a lista de processos está no arquivo Information_SCHEMA, você pode fazer isso para gerar os comandos KILL QUERY em massa a partir do cliente mysql para consultas em execução por mais de 20 minutos (1200 segundos):
SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery
FROM information_schema.processlist WHERE user<>'system user'
AND time >= 1200\G
Você pode fazer cláusulas WHERE no campo INFO para procurar uma consulta específica, o campo TIME em consultas demoradas ou o campo DB em um banco de dados específico.
Se você é root @ localhost, deve ter privilégios totais para executar isso da seguinte maneira
SECONDS_TOO_LONG=1200
KILLPROC_SQLSTMT="SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" | mysql -uroot -ppassword
Você pode criar isso da seguinte maneira:
SECONDS_TOO_LONG=1200
QUERIES_RUNNING_TOO_LONG=`mysql -uroot -ppassword -ANe"SELECT COUNT(1) FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"`
if [ ${QUERIES_RUNNING_TOO_LONG} -gt 0 ]
then
KILLPROC_SQLSTMT="SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" | mysql -uroot -ppassword
fi
Aqui está outra variação:
SECONDS_TOO_LONG=1200
QUERIES_RUNNING_TOO_LONG=`mysql -uroot -ppassword -ANe"SELECT COUNT(1) FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"`
if [ ${QUERIES_RUNNING_TOO_LONG} -gt 0 ]
then
KILLPROC_SQLSTMT="SELECT CONCAT('KILL QUERY ',id,';') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" > /tmp/kill_log_queries.sql
mysql -uroot -ppassword < /tmp/kill_log_queries.sql
fi
BTW Você não especificou um myDB desde que eu expliquei a leitura de information_schema.processlist como um nome de tabela totalmente qualificado.
Aqui está uma demonstração do que você deve ver. Neste exemplo, ecoarei o comando KILL de todos os processos cujo tempo> 20000 segundos:
[root@***** ~]# mysql `lwdba_connect` -ANe"SELECT GROUP_CONCAT('KILL ',id,'; ' SEPARATOR ' ') FROM information_schema.processlist WHERE time > 25000 AND user<>'system user';"
+----------------------------------------------------+
| KILL 180186; KILL 180141; KILL 176419; KILL 3; |
+----------------------------------------------------+
[root@***** ~]#
Eu tenho feito essa técnica nos últimos 5 anos. De fato, enviei essa resposta ao DBA StackExchange no ano passado e ela foi aceita .
Encontrei o seguinte código cortado aqui :
Atualização 2013-01-14: Houve uma dica anônima de que isso é potencialmente perigoso e pode também matar processos de replicação. Portanto, use por sua conta e risco:
mysql -e 'show processlist\G' |\
egrep -b5 'Time: [0-9]{2,}' |\
grep 'Id:' |\
cut -d':' -f2 |\
sed 's/^ //' |\
while read id
do
mysql -e "kill $id;"
done
No MySQL 5.7 em diante, você pode usar a variável max_execution_time para fazer isso automaticamente em todas as consultas de leitura "SELECT".
Eu não tentaria soluções bash se você gostaria de tempo de atividade!
Se você tiver acesso ao código, poderá realmente definir o tempo máximo de execução nas instruções SELECT usando o método descrito aqui :
SELECT
MAX_EXECUTION_TIME = 1000 --in milliseconds
*
FROM table;
Caso contrário, no servidor:
/programming/415905/how-to-set-a-maximum-execution-time-for-a-mysql-query
Instale pt-kill:
$ wget percona.com/get/pt-kill
Tire uma foto da sua lista de processos:
$ mysql -u root -B -pmyreallyimportantpassword -e "show processlist;" > processlist.txt
Teste pt-kill no instantâneo:
$ ./pt-kill --test-matching processlist.txt --busy-time 45 --kill-busy-commands 'Execute' --victims all --print
# 2019-02-25T17:34:37 KILL 45710302 (Execute 374 sec) SELECT\n\tCOUNT(DISTINCT(LP.sessionId))\nFROM lp_traffic LP\nINNER JOIN orders O ON O.orderId = LP.order
# 2019-02-25T17:34:37 KILL 45713515 (Execute 67 sec) SELECT \n\tCOUNT(DISTINCT(CASE WHEN T.response = 'SUCCESS' AND T.isVoid = 0 AND (T.txnType IN
Verifique se as regras de correspondência se adequam ao seu caso. Os itens acima eliminarão todas as instruções Execute por 45 segundos. Depois de ter certeza, modifique e execute este comando para executar a instrução em um intervalo de 10 segundos:
$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill