Mysql

如何安全地停止mysqldump?

  • October 4, 2017

我(嗯,我的 cron 腳本)試過killall mysqldump了,但結果並不好——mysql 伺服器在一段時間後停止接受連接。

這是 Debian Jessie 機器,帶有mysql 5.5.55-0+deb8u1.

使用場景是:

  • 有一個長時間執行(幾個小時)的SELECT查詢,要麼真的很慢,要麼發送它的客戶端有問題(查詢狀態是Sending data),但所有其他查詢都愉快地來來去去(只有負載可能略高) .
  • 在夜間備份正在執行mysqldump --max_allowed_packet=2147483648 --hex-blob --single-transaction --master-data --routines --order-by-primary --databases db1 db2 db3... | pigz -p8 > backup.sql.gz。它從未完成,可能是因為它正在等待SELECT上面的首先完成(在這裡猜測 - 這是唯一看起來不尋常的事情,並且相同的設置工作了幾個月)。
  • cron 作業在早上執行,它killall -q mysqldump應該安全地終止備份,以防它沒有在設定的時間完成(通知管理員稍後檢查並修復問題),從而允許人們繼續正常使用 mysql 伺服器。
  • 但是結果是完整的連接表,因此沒有使用者能夠登錄到 mysql 伺服器。有FLUSH /*!40101 LOCAL */ TABLES查詢卡住Waiting for table flush,數百個SELECT查詢卡在同一Waiting for table flush狀態。
  • 此外,管理員殺死LOCK TABLESmysql 查詢並沒有幫助,因為其他 SELECT 查詢仍然存在Waiting for table flush(這似乎是預期的行為?

重新啟動 mysql 伺服器終於“修復”了這個問題。但是,為了避免這種情況(和緊急管理員干預)重複,我想安全地終止 Debian Jessie mysql-5.5.55(或即將推出的 Debian Stretch mariadb-10.1.23-8)中的 mysqldump 備份。有辦法嗎?

如果不是,還有哪些其他選項可以完成 mysql 備份並避免早上的伺服器負載(在這種情況下,這幾乎與完全掛起的伺服器一樣糟糕)?

(如果可能的話,我想繼續使用 Debian Stable 軟體包)

正如@Mannoj 所建議的,我已經用更智能的版本替換了簡單的“killall -q mysqldump”,這應該可以解決問題。它在“等待表刷新”狀態下查找所有超過 4 小時的查詢並殺死它們(並生成程序列表,以便第二天可以調試問題)。

我兩次從 cron(8) 呼叫它:

  • 晚上 11 點 - 就在我開始備份之前(所以備份實際上開始了,即使當時一些長時間執行的 SELECT 仍在執行)
  • 早上 7 點,帶著“硬”的論點——就在人們開始上班之前(重新啟動 mysql 伺服器,以防沒有人可以連接到它)
#!/bin/sh
killall -q mysqldump
睡覺 3
mysql -BNe '顯示程序列表' | \
perl -nE '($id,$u,$h,$db,$cmd,$time,$state,$info) = split /\t/;
if (($time > 4*3600) and ($cmd =~ /Query/)) {
$找到++;說“顯示程序列表;”
如果 ($found==1); 說“殺死$id;”
};' | mysql -v

如果 [“$1”=“硬”]
然後
睡覺 30
mysql -BNe '顯示程序列表' | grep -q '查詢。*顯示程序列表' || /etc/init.d/mysql 重啟
是

由於您使用--master_data的是主狀態的一致值。

mysqldump 的內部將向 mysql 伺服器發出以下命令。

2017-05-31T04:39:05.843130Z    48 Query /*!40100 SET @@SQL_MODE='' */
2017-05-31T04:39:05.843273Z    48 Query /*!40103 SET TIME_ZONE='+00:00' */
2017-05-31T04:39:05.843411Z    48 Query FLUSH /*!40101 LOCAL */ TABLES
2017-05-31T04:39:05.846031Z    48 Query FLUSH TABLES WITH READ LOCK
2017-05-31T04:39:05.846166Z    48 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
2017-05-31T04:39:05.846279Z    48 Query START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */
2017-05-31T04:39:05.846413Z    48 Query SHOW MASTER STATUS
2017-05-31T04:39:05.846539Z    48 Query UNLOCK TABLES
..
..... Here it continues to take backup of data and structures .

發生了什麼事?:

您的備份剛剛開始,並且在 FLUSH TABLES 命令之前,有一個查詢在特定表上執行了更長的時間,並且沒有釋放表上的鎖,並且FLUSH TABLES必須一直在等待該執行緒完成或繼續嘗試刷新,直到該表的 revision_version 與所有表相同。

因此,您也會為其他表阻塞其他執行緒。因為這是在刷新表進行時整個 DBs*.Tables* 級別的鎖。最後,它會累積程序列表中的每個新連接並堆積起來,直到max_connections不允許任何人登錄。

假設您已成功登錄終端並試圖殺死刷新表,我認為沒有辦法拉回或回滾已完成的刷新表並釋放其自己的執行緒連接。所以它可能會在KILLED STATE更長的時間內。因此,您可能已經達到了重新啟動伺服器的最後一個選項。

如何解決?:

在發佈時,當管理員設法登錄到 mysql 提示符時。

而不是在 FLUSH TABLES 執行緒上發出 kill 命令,如果給執行 long SELECT 的執行緒提供了kill 命令。有可能 SELECT 會被刪除並且表會被 FLUSH TABLES 獲取和更新 revision_version 並釋放新查詢的鎖。備份將繼續進行。因為我認為沒有人期待另一端的答案等待查詢執行很長時間的結果。

什麼是長期解決方案?:

  • 您必須確保在備份時沒有執行這麼長時間的查詢。
  • 看起來這可能是一個新部署,或者有人觸發了錯誤的查詢並且沒有費心關閉會話。
  • 如果查詢執行的時間超過 Xsecs(取決於您的要求),請嘗試終止查詢。要麼
  • 與團隊進行調整以調整查詢或將其發送給管理員以給他們結果數據或給他們一個單獨的從屬。

引用自:https://dba.stackexchange.com/questions/174957