Làm cách nào để tự động giết các truy vấn MySQL chậm sau N giây?


16

Tôi đang tìm kiếm một tập lệnh bash được thử nghiệm tốt (hoặc giải pháp thay thế) để làm như vậy, để tránh max_connection bị cạn kiệt. Tôi biết rằng nó đang chiến đấu với các triệu chứng, nhưng thực sự cần kịch bản như một giải pháp ngắn hạn.


Phiên bản MySQL nào bạn đang chạy ???
RolandoMySQLDBA

phiên bản mysql là 5.5
alfish

Câu trả lời:


21

kiểm tra lệnh pt-kill từ bộ công cụ percona .

và .. hãy bắt đầu theo dõi hệ thống của bạn - munin , cacti với các mẫu xương rồng tốt hơn cho mysql , bất cứ điều gì để bạn biết một số ý tưởng đang diễn ra. đăng nhập truy vấn chậm mysql cũng sẽ là một ý tưởng tốt.


Cảm ơn về các đề xuất, nhưng thực sự tìm kiếm một kịch bản "một lần".

5
pt-kill được kiểm tra rất tốt và giải quyết vấn đề chính xác của bạn. Phải mất 10 phút để tìm ra các tham số dòng lệnh và chạy nó. Nhiều hơn những gì bạn muốn?
Aaron Brown

12

Nếu bạn có MySQL 5.1 trong đó danh sách quy trình nằm trong Information_SCHema, bạn có thể thực hiện việc này để tạo hàng loạt lệnh KILL QUERY từ bên trong máy khách mysql để truy vấn chạy dài hơn 20 phút (1200 giây):

SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery
FROM information_schema.processlist WHERE user<>'system user'
AND time >= 1200\G

Bạn có thể thực hiện các mệnh đề WHERE đối với trường INFO để tìm kiếm một truy vấn cụ thể, trường TIME đối với các truy vấn chạy dài hoặc trường DB đối với cơ sở dữ liệu cụ thể.

Nếu bạn là root @ localhost, bạn nên có đầy đủ đặc quyền để chạy nó như sau

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

Bạn có thể crontab này như sau:

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

Đây là một biến thể khác:

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 Bạn không chỉ định myDB vì tôi đã đọc rõ ràng từ information_schema. Processlist dưới dạng tablename đủ điều kiện.

Dưới đây là một minh chứng về những gì bạn nên xem. Trong ví dụ này, tôi sẽ lặp lại lệnh KILL của tất cả các quy trình có thời gian> 20000 giây:

[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@***** ~]#

Tôi đã làm kỹ thuật này trong 5 năm qua. Trên thực tế, tôi đã gửi câu trả lời này cho DBA StackExchange vào năm ngoái và nó đã được chấp nhận .


Roland, bạn có thể vui lòng làm rõ những điều sau: Lệnh này có liên tục hay cần được chạy thường xuyên? Điều gì nên được thay thế trong lệnh giả sử rằng người dùng mysql là 'root' và tên cơ sở dữ liệu là myDB? Cảm ơn

Tôi cập nhật câu trả lời của tôi.
RolandoMySQLDBA

Cảm ơn, nhưng sau khi biến công thức cuối cùng của bạn thành tập lệnh bash, tôi nhận được: ERROR 1064 (42000) ở dòng 1: Bạn gặp lỗi trong cú pháp SQL của mình; kiểm tra hướng dẫn tương ứng với phiên bản máy chủ MySQL của bạn để biết đúng cú pháp để sử dụng gần '' ở dòng 1
alfish

Lệnh SQL nào tạo ra lỗi đó ???
RolandoMySQLDBA

Roland SF không phải là một hộp cát. Tốt hơn để kiểm tra trước khi bạn đề xuất một cái gì đó như là giải pháp. Ngoài ra, khi tất cả các kết nối đã bão hòa, làm thế nào mysql sẽ chạy thủ tục của bạn, giả sử rằng nó không bị lỗi?

6

Tôi tìm thấy đoạn mã sau đây ở đây :

Cập nhật 2013-01-2014: Có một gợi ý ẩn danh rằng điều này có khả năng nguy hiểm và cũng có thể giết chết các quá trình sao chép. Vì vậy, sử dụng có nguy cơ của riêng bạn:

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

Hằng số thời gian trong đoạn trích trên là gì?

@alfish Tôi không phải là tác giả - nhưng tôi sẽ nói đây là biểu thức chính quy khớp với tất cả các giá trị thời gian có ít nhất hai chữ số. Vì vậy, giả định ở đây là 10 là quá dài.
Nils

1

MySQL 5.7 trở đi, bạn có thể sử dụng biến max_execut_time để thực hiện điều này tự động cho tất cả các truy vấn đọc "CHỌN".


0

Tôi sẽ không thử các giải pháp bash nếu bạn thích thời gian hoạt động!

Nếu bạn có quyền truy cập vào mã, bạn thực sự có thể đặt thời gian thực hiện tối đa cho các câu lệnh CHỌN bằng cách sử dụng phương pháp được nêu ở đây :

SELECT 
MAX_EXECUTION_TIME = 1000 --in milliseconds
* 
FROM table;

Mặt khác, trên máy chủ:

/programming/415905/how-to-set-a-maximum-execut-time-for-a-mysql-query

Cài đặt pt-kill:

$ wget percona.com/get/pt-kill

Chụp nhanh danh sách quy trình của bạn:

$ mysql -u root -B -pmyreallyimportantpassword -e "show processlist;" > processlist.txt

Kiểm tra pt-kill trên ảnh chụp nhanh:

$ ./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

Hãy chắc chắn rằng các quy tắc phù hợp với trường hợp của bạn. Những điều trên sẽ giết tất cả các câu lệnh Execute trong hơn 45 giây. Khi bạn chắc chắn sau đó sửa đổi và chạy lệnh này để thực thi câu lệnh trong khoảng thời gian 10 giây:

$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.