ローカルのmysqlが死んだときの備忘録
環境
mysql 5.7.16
macOS 10.12.4
mysqlcheck Ver 2.5.1 Distrib 5.7.16, for osx10.11 (x86_64)
起きたこと
普段通りによくあるrailsのspecを通していたら、全部通らなくなった。エラーを見るとmysqlのコネクションエラー系のやつ。rails sでサーバーは起動できるが、specは通らない。mysqlcheckをしても復旧には至らず。
Mysql2::Error: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
あぁ、なんか知らないけどlocalのmysqlが死んだんだなと起動してみるも、起動しない
[kenta.miyachi]% sudo mysql.server start Password: Starting MySQL .. ERROR! The server quit without updating PID file (/usr/local/var/mysql/MKenta.local.pid).
む、なにかおかしいなと思い、エラーログを見てみる。いっぱい出ていた。
2017-04-17 19:57:17 0x70000728a000 InnoDB: Assertion failure in thread 123145422413824 in file trx0purge.cc line 168 InnoDB: Failing assertion: purge_sys->iter.trx_no <= purge_sys->rseg->last_trx_no InnoDB: We intentionally generate a memory trap. InnoDB: Submit a detailed bug report to http://bugs.mysql.com. InnoDB: If you get repeated assertion failures or crashes, even InnoDB: immediately after the mysqld startup, there may be InnoDB: corruption in the InnoDB tablespace. Please refer to InnoDB: http://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html InnoDB: about forcing recovery. 10:57:17 UTC - mysqld got signal 6 ; 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.
こんな感じのmessageが出たときは、エラーログでぐぐってフォーラムを見ると良さそう。 ログから見た感じ、このbugっぽさ?でも違う気もする。完全に同じものは見つからず。 https://bugs.mysql.com/bug.php?id=61516
復旧
とりあえず一旦は作業ができれば良いので、DBの復旧を試みる。
innodb_force_recoveryを使ってとりえあえずdataだけdumpする。
値は以下。
1: SRV_FORCE_IGNORE_CORRUPT
2: SRV_FORCE_NO_BACKGROUND
3: SRV_FORCE_NO_TRX_UNDO
4: SRV_FORCE_NO_IBUF_MERGE
5: SRV_FORCE_NO_UNDO_LOG_SCAN
6: SRV_FORCE_NO_LOG_REDO
詳しくは公式にて。
https://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html
https://dev.mysql.com/doc/refman/5.6/ja/forcing-innodb-recovery.html
[mysqld] innodb_force_recovery = 3
これで起動だけは出来たので、一旦全部dumpする。 やっていることは
- 全databaseをdump
- mysqlテーブル以外を削除して
- dumpから復元
% mysqldump -u root -p -x --all-databases > alldatabase.dump % sudo mysql.server stop % sudo rm -rf `ls -d /var/lib/mysql/* | grep -v "/var/lib/mysql/mysql"` % mysql -u root -p < alldatabase.dump
とりあえずmysqlが起動するようにはなった。 これでdump復元でうまく行けば無問題、しかしそうは問屋が卸さない
[kenta.miyachi]% mysql -u root -p < alldatabase.dump Enter password: ERROR 1813 (HY000) at line 5035: Tablespace '`mysql`.`engine_cost`' exists.
既にいるらしい、でもDROP TABLE IF EXISTSを書いているdumpなのでそんなことはないはず。直にCREATE TABLEクエリを投げてみても、同じエラー、DROPもできず。中身を見てみる。
sh-3.2# ls | grep engine engine_cost.ibd
本来 TableName.frm と TableName.ibdがいないと行けないところ、.ibdファイルしかいなかった。これが不整合の元凶なのではないかと。 とりあえず、dumpを取っているのでこいつを消してdumpから復元する。 何度か起きたので繰り返し。無事復旧完了。
.frmと .ibdについて
.frm
テーブルに関するそのデータディクショナリ情報が格納されます。
https://dev.mysql.com/doc/refman/5.6/ja/innodb-frm-file.html
.ibd
テーブル固有のテーブルスペースを持つテーブル (.ibd ファイルに格納) は、MySQL Server を停止させずに個別にリストアできます。間違ってテーブルデータを削除または更新した場合に、この手法を適用でき、DROP TABLE、TRUNCATE TABLE、または DROP DATABASE のステートメントを通じて、実際にはテーブル自体を失うことがありません。
https://dev.mysql.com/doc/mysql-enterprise-backup/3.11/ja/partial.restoring.single.html
復元中に調べていて知ったのですが、壊れたtableを特定できていれば、これで簡単に一部だけリストアできたかもしれない。今回一番の反省でした。
解決
Localなのでかなり雑にやってしまいましたが、.ibdのことを知っていればもう少し作業が楽に進んだかもしれません。 tableが壊れた原因については、別途調査中。今のところ不具合はなし。
ツッコミお待ちしております。
参考
InnoDB が破損し MySQL 全体が不安定に -
http://nlogn.ath.cx/archives/001874.html
MySQLのクラッシュバグにご用心 -
http://wadahiro.hatenablog.com/entry/20111006/1317927393
MySQLでInnoDB破損したときの復旧方法 -
http://qiita.com/skouno/items/71174c959abe435223ab
MySQLでスキーマ情報に不整合が起こったら -
http://accountingse.net/2015/09/943/