Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@syogun

mysql starting-crash-recoveryからのリカバリ(DBが削除できない)

More than 5 years have passed since last update.

概要

Percona xtrabackupを使用したバックアップ、リストアでハマったこと
でxtrabackupを使用したリストア処理中にDISCARD TABLEスペース処理で失敗し、
そこから「starting-crash-recovery」がとなった時の対応を書きます。
今回実行したリストアスクリプトは、ざっくり

  • DROP TABLE(DBの全テーブル)
  • CREATE TABLE(mysqldump --no-dataで出力されたものを使ってインポート)
  • ALTER TABLE テーブル名 DISCARD TABLESPACE ※外部キー制約などでここで失敗して、リストアがこけていた。
  • ALTER TABLE テーブル名 IMPORT TABLESPACE

という処理をしていました。

環境

$ cat /etc/redhat-release
CentOS release 6.4 (Final)
$ mysql --version
mysql  Ver 14.14 Distrib 5.6.12, for Linux (x86_64) using  EditLine wrapper

やったこと

まず、mysqlを再起動しようと思い、sudo service mysql restart を実行したところ以下のエラーが出力された。

ERROR! MySQL server PID file could not be found!

mysqld.logを確認すると同じテーブルに対し何度もを「starting-crash-recovery」を実行している状態だった。
事象としては、以下の記事と同じものだった。
MySQLが何度も「Starting crash recovery」を実行する

しばらく様子を見てもいっこうに状況が変わらないため、一旦kill -9でプロセスをmysqlプロセス強制停止。
my.cnfの [mysqld] に「innodb_force_recovery」を設定して強制リカバリモードで起動してみることに。
innodb_force_recoveryは1から6まで設定でき、1から順に実行して、復旧しなければ2といった感じで徐々に数値を上げてrecoveryを行うようだ。
強制リカバリの処理内容は以下のページを参照
InnoDB のリカバリの強制的な実行

今回は、「innodb_force_recovery=4」でmysqldが起動することを確認した。
「ALTER TABLE テーブル名 DISCARD TABLESPACE;」の途中で止まっていたので、再度実行してみる。(当然、InnoDB以外のテーブルは失敗するがとりあえずスキップ)
「ALTER TABLE テーブル名 IMPORT TABLESPACE;」を実行してみる。

ERROR 1036 (HY000): Table 'area' is read only

読み取り専用になっている?
どうやらIMPORT TABLESPACEもできないようになっている。
では一旦、元のリストアスクリプトを実行してみようということで、リストアを開始するもこける。。
それならとDROP DATABASEで今回リストアに失敗したDBを削除し、再度リストアしてみてみようということに。

mysql> drop database <DB名>
ERROR 1051 (42S02): Unknown table 'DB名.テーブル名,DB名.テーブル名,DB名.テーブル名'

試しにCREATE TABLEしてもダメ

mysql> create table testtest (id integer);
ERROR 1036 (HY000): Table 'testtest' is read only

DBも削除できない。。。原因はこれだった。

MySQL 5.6.15 の時点では、4 以上の innodb_force_recovery 設定は InnoDB を読み取り専用モードにします。

さきほどinnodb_force_recoveryを「4」で起動していたことが原因だった。
innodb_force_recoveryを外して、mysqlを再起動し、再度DROP TABLEをリトライ。

ERROR 2013 (HY000): Lost connection to MySQL server during query

困った。DBが削除できない。
次に前日に取得していたバックアップを展開し、データディレクトリ(/var/lib/mysq/DB名)を差し替えてみることに。
mysqlは起動するが、select文を実行すると以下のエラーが出力される。

ERROR 1016 (HY000): db not initialized

いよいよやることがなくなって、最後の手段としてinnodb_force_recoveryの「5」を試してみる → 変化なし。
innodb_force_recoveryの「6」 を試してみる。mysqld.logから以下のログ出力が消える。

InnoDB: DISCARD flag set for table '"DB名"."テーブル名"', ignored.

ここで再度DROP DATABASEにトライ。

mysql> drop database <DB名>;
ERROR 1010 (HY000): Error dropping database (can't rmdir './<DB名>', errno: 39)

上記エラーは、データディレクトリ(/var/lib/mysq/DB名)配下のファイルを主導で削除すると良いらしい。

$ rm -f /var/lib/mysq/DB名/*

mysql> drop database <DB名>;
Query OK, 0 rows affected (0.00 sec) 

念願のDBの削除完了!
これでDBが削除できたため、リストアを再実行して復旧完了。

まとめ

そもそも検証が十分されたいなかったことを反省しています。改めて検証が大事だと痛感。
あとは誤算だったのは、DBが削除できないという想定外の事象に遭遇したこと。
最終的には、innodb_force_recoveryの「6」という力技?でDBを削除できるようになった。
しかしこれは最終手段として使うと良いのかもしれません。
innodb_force_recoveryの「6」のドキュメントは以下。

6 (SRV_FORCE_NO_LOG_REDO)
リカバリに関連した Redo ログのロールフォワードを実行しません。
この値を指定すると、データファイルが永続的に破損する場合があります。
データベースページを廃止された状態のままにし、
それによって B ツリーやその他のデータベース構造にさらに多くの破損が発生する可能性があります。
MySQL 5.6.15 の時点では、InnoDB を読み取り専用に設定します。
1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
syogun

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?