Я ищу хорошо протестированный bash-скрипт (или альтернативное решение) для этого, чтобы избежать исчерпания max_connection. Я знаю, что это борется с симптомами, но действительно нужен такой сценарий, как краткосрочное решение.
Я ищу хорошо протестированный bash-скрипт (или альтернативное решение) для этого, чтобы избежать исчерпания max_connection. Я знаю, что это борется с симптомами, но действительно нужен такой сценарий, как краткосрочное решение.
Ответы:
проверьте команду pt-kill из набора инструментов Percona .
и ... начните контролировать свою систему - munin , cacti с лучшими шаблонами cacti для mysql , что угодно, чтобы вы поняли, что происходит. регистрация медленных запросов mysql также будет хорошей идеей.
Если у вас есть MySQL 5.1, где список процессов находится в INFORMATION_SCHEMA, вы можете сделать это для генерации массовых команд KILL QUERY из клиента mysql для запроса, выполняющегося более 20 минут (1200 секунд):
SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery
FROM information_schema.processlist WHERE user<>'system user'
AND time >= 1200\G
Вы можете использовать предложения WHERE для поля INFO, чтобы искать конкретный запрос, поле TIME для длительных запросов или поле DB для конкретной базы данных.
Если вы являетесь пользователем root @ localhost, у вас должны быть полные привилегии для выполнения этого следующим образом
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
Вы можете crontab это следующим образом:
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
Вот еще один вариант:
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
Кстати, вам не нужно указывать myDB, так как я явно прочитал из information_schema.processlist как полное имя таблицы.
Вот демонстрация того, что вы должны увидеть. В этом примере я выведу команду KILL для всех процессов, время которых> 20000 секунд:
[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@***** ~]#
Я делаю эту технику в течение последних 5 лет. Фактически, я представил этот ответ в DBA StackExchange в прошлом году, и он был принят .
Я нашел следующий фрагмент кода здесь :
Обновление 2013-01-14: был анонимный намек на то, что это потенциально опасно и может привести к остановке процессов репликации. Так что используйте на свой страх и риск:
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
В MySQL 5.7 и далее вы можете использовать переменную max_execution_time, чтобы сделать это автоматически для всех запросов чтения SELECT.
Я не стал бы пробовать решения bash, если вам нравится uptime!
Если у вас есть доступ к коду, вы можете установить максимальное время выполнения операторов SELECT, используя метод, описанный здесь :
SELECT
MAX_EXECUTION_TIME = 1000 --in milliseconds
*
FROM table;
В противном случае на сервере:
/programming/415905/how-to-set-a-maximum-execution-time-for-a-mysql-query
Установите pt-kill:
$ wget percona.com/get/pt-kill
Сделайте снимок вашего списка процессов:
$ mysql -u root -B -pmyreallyimportantpassword -e "show processlist;" > processlist.txt
Проверьте pt-kill на снимке:
$ ./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
Убедитесь, что правила матча соответствуют вашему случаю. Это выше убьет все операторы Execute за 45 секунд. Если вы уверены, измените и выполните эту команду, чтобы выполнить инструкцию с интервалом в 10 секунд:
$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill