MySQLデータベースは複数の方法で停止できます。いくつかの明白な方法は、ホストをシャットダウンするか、電源ケーブルを抜くか、またはSIGKILLを使用してmysqldプロセスをハードキルして、汚れたMySQLシャットダウン動作をシミュレートすることです。しかし、MySQLサーバーを故意にクラッシュさせて、それがどのような連鎖反応を引き起こすかを確認するための、それほど巧妙ではない方法もあります。なぜあなたはこれをしたいのですか?障害と回復には多くのコーナーケースがあり、それらを理解することで、本番環境で発生した場合の驚きの要素を減らすことができます。理想的には、制御された環境で障害をシミュレートしてから、データベースのフェイルオーバー手順を設計およびテストすることをお勧めします。
MySQLには、失敗またはクラッシュの方法に応じて、取り組むことができるいくつかの領域があります。表領域を破損したり、MySQLバッファとキャッシュをオーバーフローさせたり、リソースを制限してサーバーを枯渇させたり、権限をいじったりする可能性があります。このブログ投稿では、Linux環境でMySQLサーバーをクラッシュさせる方法の例をいくつか紹介します。それらのいくつかは、例えばに適しているでしょう。基盤となるホストにアクセスできないAmazonRDSインスタンス。
殺す、殺す、殺す、死ぬ、死ぬ、死ぬ
MySQLサーバーに障害を発生させる最も簡単な方法は、プロセスまたはホストを強制終了することであり、MySQLに正常なシャットダウンを実行する機会を与えないことです。 mysqldのクラッシュをシミュレートするには、シグナル4、6、7、8、または11をプロセスに送信するだけです。
$ kill -11 $(pidof mysqld)
MySQLエラーログを見ると、次の行が表示されます。
11:06:09 UTC - mysqld got signal 11 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
Attempting to collect some information that could help diagnose the problem.
As this is a crash and something is definitely wrong, the information
collection process might fail.
..
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
また、kill -9(SIGKILL)を使用して、プロセスをすぐに強制終了することもできます。 Linuxシグナルの詳細については、こちらをご覧ください。または、電源ケーブルを抜く、ハードリセットボタンを押す、フェンシングデバイスを使用してSTONITHに接続するなど、ハードウェア側で意味のある方法を使用することもできます。
トリガーOOM
AmazonRDSやGoogleCloudSQLなどのクラウド製品で人気のあるMySQLには、それらをクラッシュさせる簡単な方法がありません。 1つは、データベースインスタンスへのOSレベルのアクセスがないため、もう1つは、プロバイダーが独自のパッチを適用したMySQLサーバーを使用しているためです。 1つの方法は、一部のバッファをオーバーフローさせ、メモリ不足(OOM)マネージャにMySQLプロセスを開始させることです。
ソートバッファサイズをRAMが処理できるサイズよりも大きくして、MySQLサーバーに対して多数のmysqlソートクエリを実行できます。 Amazon RDSインスタンスでsysbenchを使用して1,000万行のテーブルを作成し、巨大な並べ替えを作成できるようにします。
$ sysbench \
--db-driver=mysql \
--oltp-table-size=10000000 \
--oltp-tables-count=1 \
--threads=1 \
--mysql-host=dbtest.cdw9q2wnb00s.ap-tokyo-1.rds.amazonaws.com \
--mysql-port=3306 \
--mysql-user=rdsroot \
--mysql-password=password \
/usr/share/sysbench/tests/include/oltp_legacy/parallel_prepare.lua \
run
sort_buffer_sizeを変更します Amazon RDSダッシュボード->パラメーターグループ->パラメーターグループの作成->グループ名の指定->パラメーターの編集->「sort_buffer_size」を選択して5G(テストインスタンスはdb.t2.micro-1GB、1vCPU)に移動し、値は5368709120です。
[インスタンス]->[インスタンスアクション]->[変更]->[データベースオプション]->[データベースパラメーターグループ]->に移動し、新しく作成したパラメーターグループを選択して、パラメーターグループの変更を適用します。次に、RDSインスタンスを再起動して変更を適用します。
起動したら、 sort_buffer_sizeの新しい値を確認します :
MySQL [(none)]> select @@sort_buffer_size;
+--------------------+
| @@sort_buffer_size |
+--------------------+
| 5368709120 |
+--------------------+
次に、クライアントからの並べ替えを必要とする48の単純なクエリを実行します。
$ for i in {1..48}; do (mysql -urdsroot -ppassword -h dbtest.cdw9q2wnb00s.ap-tokyo-1.rds.amazonaws.com -e 'SELECT * FROM sbtest.sbtest1 ORDER BY c DESC >/dev/null &); done
上記を標準ホストで実行すると、MySQLサーバーが終了し、OSのsyslogまたはdmesgに次の行が表示されます。
[164199.868060] Out of memory: Kill process 47060 (mysqld) score 847 or sacrifice child
[164199.868109] Killed process 47060 (mysqld) total-vm:265264964kB, anon-rss:3257400kB, file-rss:0kB
systemdを使用すると、MySQLまたはMariaDBが自動的に再起動され、AmazonRDSも再起動されます。 RDSインスタンスの稼働時間が0にリセットされ(mysqladminステータスの下)、「最新の復元時間」の値(RDSダッシュボードの下)がダウンした瞬間に更新されることがわかります。
データの破損
InnoDBには、データディクショナリ、バッファー、およびロールバックセグメントをibdata1という名前のファイル内に格納するための独自のシステムテーブルスペースがあります。 innodb_file_per_table(MySQL 5.6.6以降ではデフォルトで有効)を構成しない場合は、共有テーブルスペースも格納されます。このファイルをゼロにし、書き込み操作を送信し、テーブルをフラッシュしてmysqldをクラッシュさせることができます:
# empty ibdata1
$ cat /dev/null > /var/lib/mysql/ibdata1
# send a write
$ mysql -uroot -p -e 'CREATE TABLE sbtest.test (id INT)'
# flush tables
$ mysql -uroot -p -e 'FLUSH TABLES WITH READ LOCK; UNLOCK TABLES'
書き込みを送信すると、エラーログに次のように表示されます。
2017-11-15T06:01:59.345316Z 0 [ERROR] InnoDB: Tried to read 16384 bytes at offset 98304, but was only able to read 0
2017-11-15T06:01:59.345332Z 0 [ERROR] InnoDB: File (unknown): 'read' returned OS error 0. Cannot continue operation
2017-11-15T06:01:59.345343Z 0 [ERROR] InnoDB: Cannot continue operation.
この時点で、mysqlは操作を実行できないためハングし、フラッシュ後、「mysqld got signal 11」行が表示され、mysqldはシャットダウンします。クリーンアップするには、破損したibdata1とib_logfile *を削除する必要があります。これは、次回の再起動時にmysqldによって生成される新しいシステムテーブルスペースでREDOログファイルを使用できないためです。データの損失が予想されます。
MyISAMテーブルの場合、MySQLデータディレクトリの下で.MYD(MyISAMデータファイル)と.MYI(MyISAMインデックス)をいじることができます。たとえば、次のコマンドは、ファイル内で出現する文字列「F」を「9」に置き換えます。
$ replace F 9 -- /var/lib/mysql/sbtest/sbtest1.MYD
次に、いくつかの書き込み(sysbenchを使用するなど)をターゲットテーブルに送信し、フラッシュを実行します。
mysql> FLUSH TABLE sbtest.sbtest1;
MySQLエラーログには次のように表示されます。
2017-11-15T06:56:15.021564Z 448 [ERROR] /usr/sbin/mysqld: Incorrect key file for table './sbtest/sbtest1.MYI'; try to repair it
2017-11-15T06:56:15.021572Z 448 [ERROR] Got an error from thread_id=448, /export/home/pb2/build/sb_0-24964902-1505318733.42/rpm/BUILD/mysql-5.7.20/mysql-5.7.20/storage/myisam/mi_update.c:227
MyISAMテーブルはクラッシュしたものとしてマークされ、再度アクセスできるようにするにはREPAIRTABLEステートメントを実行する必要があります。
リソースの制限
オペレーティングシステムのリソース制限をmysqldプロセスに適用することもできます。たとえば、開いているファイル記述子の数などです。 open_file_limit変数(デフォルトは5000)を使用すると、mysqldはsetrlimit()コマンドを使用してファイル記述子を予約できます。この変数を比較的小さく設定して(mysqldが起動するのに十分なだけ)、制限に達するまで複数のクエリをMySQLサーバーに送信できます。
mysqldがsystemdサーバーで実行されている場合は、/ usr / lib / systemd / system / mysqld.serviceにあるsystemdユニットファイルで設定し、次の値をより低い値に変更できます(systemdのデフォルトは6000):
# Sets open_files_limit
LimitNOFILE = 30
systemdに変更を適用し、MySQLサーバーを再起動します:
$ systemctl daemon-reload
$ systemctl restart mysqld
次に、異なるデータベースとテーブルでカウントされる新しい接続/クエリの送信を開始して、mysqldが複数のファイルを開かなければならないようにします。次のエラーが表示されます:
2017-11-16T04:43:26.179295Z 4 [ERROR] InnoDB: Operating system error number 24 in a file operation.
2017-11-16T04:43:26.179342Z 4 [ERROR] InnoDB: Error number 24 means 'Too many open files'
2017-11-16T04:43:26.179354Z 4 [Note] InnoDB: Some operating system error numbers are described at http://dev.mysql.com/doc/refman/5.7/en/operating-system-error-codes.html
2017-11-16T04:43:26.179363Z 4 [ERROR] InnoDB: File ./sbtest/sbtest9.ibd: 'open' returned OS error 124. Cannot continue operation
2017-11-16T04:43:26.179371Z 4 [ERROR] InnoDB: Cannot continue operation.
2017-11-16T04:43:26.372605Z 0 [Note] InnoDB: FTS optimize thread exiting.
2017-11-16T04:45:06.816056Z 4 [Warning] InnoDB: 3 threads created by InnoDB had not exited at shutdown!
この時点で、制限に達すると、MySQLはフリーズし、操作を実行できなくなります。接続しようとすると、しばらくすると次のように表示されます。
$ mysql -uroot -p
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104
権限をめちゃくちゃにする
mysqldプロセスは「mysql」ユーザーによって実行されます。つまり、アクセスする必要のあるすべてのファイルとディレクトリはmysqlユーザー/グループによって所有されます。権限と所有権を台無しにすることで、MySQLサーバーを役に立たなくすることができます:
$ chown root:root /var/lib/mysql
$ chmod 600 /var/lib/mysql
サーバーへの負荷を生成してから、MySQLサーバーに接続し、すべてのテーブルをディスクにフラッシュします。
mysql> FLUSH TABLES WITH READ LOCK; UNLOCK TABLES;
現時点では、mysqldはまだ実行中ですが、ちょっと役に立たないです。 mysqlクライアントを介してアクセスできますが、操作はできません:
mysql> SHOW DATABASES;
ERROR 1018 (HY000): Can't read dir of '.' (errno: 13 - Permission denied)
混乱を解消するには、適切な権限を設定します。
$ chown mysql:mysql /var/lib/mysql
$ chmod 750 /var/lib/mysql
$ systemctl restart mysqld
ロックダウン
読み取りロック付きフラッシュテーブル(FTWRL)は、さまざまな状況で破壊的になる可能性があります。たとえば、すべてのノードが書き込みを処理できるGaleraクラスターでは、このステートメントを使用して、ノードの1つからクラスターをロックダウンできます。このステートメントは、ロックが解除されるまで、フラッシュ中にmysqldによって処理される他のクエリを単に停止します。これは、バックアッププロセス(MyISAMテーブル)およびファイルシステムスナップショットに非常に便利です。
このアクションはロック中にデータベースサーバーをクラッシュさせたりダウンさせたりすることはありませんが、ロックを保持しているセッションがロックを解放しない場合、結果は非常に大きくなる可能性があります。これを試すには、次のようにします。
mysql> FLUSH TABLES WITH READ LOCK;
mysql> exit
次に、 max_connections に到達するまで、一連の新しいクエリをmysqldに送信します。 価値。もちろん、外出すると前のセッションと同じセッションに戻ることはできません。したがって、ロックは無限に実行され、ロックを解放する唯一の方法は、別のSUPER特権ユーザー(別のセッションを使用)によってクエリを強制終了することです。または、mysqldプロセス自体を強制終了するか、ハードリブートを実行します。
免責事項
このブログは、MySQLで障害シナリオをシミュレートするためのシステム管理者とDBAの代替手段を提供するために書かれています。これらを本番サーバーで試さないでください:-)