私(まあ、私のcronスクリプト)はkillall mysqldump
を試してみましたが、うまくいきませんでした-mysqlサーバーがしばらくして接続の受け入れを停止しました。
mysql 5.5.55-0+deb8u1
を備えたDebian Jessieマシンでした。
使用シナリオは次のとおりです。
長時間(数時間)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
状態でスタックしました。
さらに、他のSELECTクエリがLOCK TABLES
に残っているため、Waiting for table flush
mysqlクエリを管理者が強制終了しても役に立たなかった(これは 意図された動作? のようです)
Mysqlサーバーを再起動すると、最終的に問題が「修正」されました。ただし、この状況(および緊急の管理者介入)の繰り返しを回避したいので、安全にDebian Jessie mysql-5.5.55のmysqldumpバックアップを終了します(または今後のDebian Stretch mariadb-10.1.23-8)。方法はありますか?
そうでない場合、mysqlバックアップを実行し、午前中にサーバーの負荷を回避するためのその他のオプションは何ですか(これは-この場合-サーバーが完全にハングしているのとほぼ同じくらい悪い)。
(可能な限り、Debian Stableパッケージを使い続けたいです)
@Mannojが示唆しているように、私は単純な「killall -q mysqldump」を問題を解決するよりスマートなバージョンに置き換えました。状態が「テーブルフラッシュを待機しています」で4時間以上前のすべてのクエリを探し、それらを強制終了します(そして、問題を翌日にデバッグできるようにプロセスリストを生成します)。
私はそれをcron(8)から2回呼び出します:
#!/ bin/sh killall -q mysqldump sleep 3 mysql -BNe 'show processlist' |\ Perl -nE '($ id、$ u、$ h、$ db、$ cmd、$ time、$ state、$ info)= split/\ t /; if(($ time> 4 * 3600)and($ cmd =〜/ Query /)){ $ found ++; 「プロセスリストを表示」と言います。 if($ found == 1); 「$ idを殺す」と言う }; ' | mysql -v if ["$ 1" = "hard"] then sleep 30 mysql -BNe 'show processlist' | grep -q 'Query。* show processlist' || /etc/init.d/mysql restart fi
--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がすべてのテーブルと同じになるまでフラッシュを続けます。
したがって、他のスレッドも他のテーブルに対してブロックされます。これは、テーブルのフラッシュが行われている間、DB * .Tables *レベルのロック全体であるためです。最後に、すべての新しい接続がプロセスリストに蓄積され、max_connections
まで蓄積され、誰もログインできないようにします。
ターミナルにログインしてフラッシュテーブルを強制終了しようとした場合、フラッシュされたテーブルをプルバックまたはロールバックして、独自のスレッド接続を解放する方法はないと思います。そのため、より長い時間KILLED STATE
になる可能性があります。したがって、サーバーを再起動するという最後のオプションに達している可能性があります。
修正方法::
問題の時点で、管理者がmysqlプロンプトにログインできたとき。
FLUSH TABLESスレッドでkillコマンドを発行する代わりに、長いSELECTを実行しているスレッドにkillが指定された場合。新しいクエリのロック。そしてバックアップは継続されたでしょう。長い時間実行されているクエリの結果を待っている相手側で回答を期待している人はいないと思います。
長期的な解決策は何ですか?:
バックアップ時にそのような長時間のクエリが実行されないようにする必要があります。
これは新しい展開の可能性があるか、誰かが不正なクエリをトリガーしてセッションを閉じようとしませんでした。
クエリがXsecsより多く実行されている場合は、クエリを強制終了してみてください(要件によって異なります)。または
コメントのレピュテーション制限のため、テストするには2つのオプションがあると思います。mysqldumpを安全に停止することは、この問題を解決する良い方法ではないと思います。
max_allowed_packet
最近、データベースが突然大きくなっていますか?
許可されている2Gを示しています。
2Gを超えるデータの場合、プロセスがハングします。
あなたが試すことができます --lock-tables=false
またはskip-add-locks
in my.cnf
ロックされたテーブルを無効にします。