って状況から脱出するというお仕事をしたのでメモ。 DROP TABLE でも、単純に rm してしまったら、でも同じ。今回の状況は次の通り。
- バックアップなし、レプリケーションもしてないので binlog もない
- MyISAM が数十テーブル、合計 20GB 弱
- datadir のパーティションは /dev/sda2, ファイルシステムは ext3
1. 今すぐパーティションをアンマウント
# umount -f /dev/sda2
次のマウント時にジャーナルやinodeがクリーンアップされてしまうので、再起動とか remount は厳禁。 (ro は大丈夫かも)
一方で今まで動いてた mysql は身動きできなくなってしまうのでこっちも stop する。同じパーティション上に存在する他のテーブルに対する flush されてない変更は失われてしまうけど、それが実行されて上書きされると元も子もないので思い切って止める。
2. 現状を丸々ディスクイメージとして保存
# dd bs=4M if=/dev/sda2 of=/somewhere/image
現状のパーティションをディスクイメージとして、十分容量のあるどこかにまるまるダンプ。
容量が足りない!って時は裏技として dd bs=4M if=/dev/sda2 | gzip -c /somewhere/image.gz
とかやって gzip 掛けながらダンプ。今回のだと重複テキストの多いデータベースだったので 500MB ぐらいに縮んだ。
これが完了した時点で、元のパーティションはもう変更されても問題ない。必要であれば remount して、削除してしまった以外のデータベースについて mysql を復活させることができる。ただ、必要がないのであれば umount したまま(止めたまま)にしておいた方が無難。複数 DB をまたいで参照するようなサービスを運用していた場合は、そもそも不整合が発生してしまうので復活させてはいけない。ケースバイケース。
3. extundelete をダウンロード & ビルド
extundelete は、 ext3/4 向けの削除ファイル復元ツール。
Fedora 16 など extundelete をバイナリで取得できるディストリビューションであれば yum なり apt-get なりで導入できる。ただそうでないケースの方が現状多いので、自前でビルドする。基本的に tar を展開して ./configure && make
すればひとまず src の下に extundelete
コマンドができるはず。ビルドには e2fslibs などが必要なので、適宜 apt-get するなりなんなりで足す。パッケージが足りてるのにビルドできない!って時はもはや gcc とかが古いので、別の新しい環境に上で作ったイメージをコピーして作業。(今回はそうするために前節のgzipで圧縮、をやった)
一般的に、ファイルを削除してしまった同じ環境上で、新しいツールのインストールやビルドといった write の発生する処理をやるのは怖いイメージがある(自分だけかもしれない)けど、今回はすでにイメージを取っているので何やっても大丈夫。
4. いざ復元
# extundelete --restore-all /somewhere/image
これだけ。その他のオプションは特に要らない。実行すると、カレントディレクトリに RECOVERED_FILES というディレクトリができ、その中にどんどん救出されたファイルが出てくる。すんばらしい。必要であれば削除した日時でフィルタリングしたり、ファイル名を直に指定して復元したりできるので、その辺はドキュメントを参照。
一通り終わってディレクトリを見てみて、 myisamchk *.MYI
とか掛けてみる。あれ、 table.MYD not found ? どうもファイルが足りない?
extundelete はどうも 0 バイトのファイルは復元してくれない模様。空のテーブルの MYD ファイルは 0 バイトなので、元々空だったな、と思ったら touch table.MYD とかで作ってしまうのも手。でもどうも違う気がする、場合は次に続く。
5. 漏れたファイルは名前を指定して復元
# extundelete --restore-file path/to/table.MYD /somewhere/image
extundelete でファイル名を直に指定して救出を試みる。どうも restore-all だと見つけきらないこともあり、その場合もこのように直にパスを指定すると救出できた。
今回はこれでひとまず全部問題なく救出できた。あとは myisamchk ( -r なり -o なり ) を掛けて、ユーザー、グループ、パーミッションを確認して元の位置に移動して、 mysql を起動すれば、ジャーン!元通り。お疲れ様でした。
ファイルが足りなかった辺りで、 ext3grep (名前通り ext3 の superblock や inode を探索しつつファイルを救出するツール) も試して手動で辿るってのもやってみたりしたけど、結果的に extundelete の restore-file でも問題なく救出できて、使わなくてもよかったので特に記載せず。 HOWTO の “Manual recovery example” の手順通りにやると色々探索してる感があって面白いので、時間があれば試してみるのもいいかもしれない。ちなみにどちらのツールも、既存のファイルシステムに write する処理はないので live なパーティションで試しても安全です。