Як автоматично вбити повільні запити MySQL через N секунд?


16

Я шукаю добре перевірений сценарій bash (або альтернативне рішення), щоб зробити це, щоб уникнути вичерпання max_connection. Я знаю, що це боротьба з симптомами, але дуже потрібен такий сценарій, як короткочасне рішення.


Яку версію MySQL ви працюєте ???
RolandoMySQLDBA

версія mysql - 5.5
alfish

Відповіді:


21

перевірити команду pt-kill з інструментарію percona .

і .. почніть моніторинг вашої системи - munin , кактуси з кращими шаблонами кактусів для mysql , будь-що, щоб ви зрозуміли, що відбувається. увійти мирові запити mysql також буде хорошою ідеєю.


Дякую за пропозиції, але справді шукайте «разовий» сценарій.
alfish

5
pt-kill дуже добре перевірений і вирішує вашу точну проблему. Визначити параметри командного рядка та запустити його потрібно 10 хвилин. Що ще ти хочеш?
Аарон Браун

12

Якщо у вас є 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

Ви можете це зробити так:

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

BTW У вас не вказано 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 минулого року, і вона була прийнята .


Роланд, чи можете ви уточнити: чи є ця команда стійкою, чи потрібно її часто виконувати? Що слід замінити в команді, припускаючи, що користувач mysql "root", а ім'я бази даних - myDB? Дякую
alfish

Я оновив свою відповідь.
RolandoMySQLDBA

Дякую, але, перетворивши ваш останній рецепт у скрипт bash, я отримую: ПОМИЛКА 1064 (42000) у рядку 1: у вас є помилка у вашому синтаксисі SQL; перевірте посібник, який відповідає вашій версії сервера MySQL, чи правильно використовувати синтаксис біля '' у рядку 1
alfish

Яка команда SQL генерувала цю помилку ???
RolandoMySQLDBA

Roland SF - це не пісочниця. Краще протестуйте, перш ніж запропонувати щось як рішення. Крім того, коли всі з'єднання насичені, наскільки mysql запустить вашу процедуру, припускаючи, що вона не є несправною?
alfish

6

Я знайшов наступний код-відрізала тут :

Оновлення 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

Яка константа часу у фрагменті вище?
alfish

@alfish Я не автор - але я б сказав, що це регулярний вираз, який відповідає всім значенням часу, які мають принаймні дві цифри. Тож припущення тут таке, що 10 занадто довгий.
Нілс

1

MySQL 5.7 далі ви можете використовувати змінну max_execution_time, щоб зробити це автоматично для всіх запитів читання "SELECT".


0

Я б не намагався баш-рішень, якщо вам подобається тривалість роботи!

Якщо у вас є доступ до коду, ви можете фактично встановити максимальний час виконання для операторів 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.