そして、未検証の情報を生成しないように-翻訳は、誤って削除されたMySQLデータベースから情報を回復する方法の研究に変わりました。
テスト環境
CentOS 5.6 x86_64およびmysql 5.0.77を搭載した仮想マシンが手に入りました
テストデータベースは、MyISAMとInnoDBの両方のテーブルで作成されました。 そして、回復を確認するためのいくつかのストアドプロシージャ:
DROP DATABASE prod;
CREATE DATABASE prod;
USE prod;
CREATE TABLE table1 (
id INTEGER ,
v VARCHAR (50),
PRIMARY KEY (id)
) ENGINE=MyISAM;
CREATE TABLE table2 (
id INTEGER ,
v VARCHAR (50),
PRIMARY KEY (id)
) ENGINE=InnoDB;
DELIMITER //
CREATE PROCEDURE dorepeat(p1 INT )
BEGIN
SET @x = 0;
REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
END
//
DELIMITER ;
CREATE FUNCTION hello (s CHAR (20))
RETURNS CHAR (50) DETERMINISTIC
RETURN CONCAT( 'Hello, ' ,s, '!' );
* This source code was highlighted with Source Code Highlighter .
さて、そこにいくつかのデータを作成します:
( for i in $(seq 1 100); do echo "insert into table1 values ($i, '`md5sum <<< "$i"`');"; done; ) >> test.sql ( for i in $(seq 1 100); do echo "insert into table2 values ($i, '`md5sum <<< "$i"`');"; done; ) >> test.sql
テストシナリオは、回復の基本的な可能性を考慮するために非常に簡単に選択されています。
毛皮のような動物はいつの間にか忍び寄った
データベースに責任があり、いくつかの情報が含まれていることをすべて作成して検証した後:
mysql> select count(*) from table1; +----------+ | count(*) | +----------+ | 100 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from table2; +----------+ | count(*) | +----------+ | 100 | +----------+ 1 row in set (0.00 sec) mysql> select hello('world'); +----------------+ | hello('world') | +----------------+ | Hello, world! | +----------------+ 1 row in set (0.00 sec)
#rm -rf / var / lib / mysql / *
記事のアドバイスによると、ファイル記述子が開いたままになるようにサーバーを再起動したり、mysqlを停止したりしません(そうしないと、情報が失われ、FSに直接介入する必要があります)。
少なくともソケットが削除されたために、上記のものが機能しないことをすぐに確認できます。
#mysql エラー2002(HY000):ソケット '/var/lib/mysql/mysql.sock'を介してローカルMySQLサーバーに接続できません(2)
tcpを介して接続しようとすると、mysqlはデータベースについて何も知らず、mysqldumpは空の出力を返すため、まだがっかりします。
#mysql --protocol tcp <<< "データベースの表示;" データベース information_schema #mysqldump --protocol tcp -A -MySQLダンプ10.11 - -ホスト:localhostデータベース: ------------------------------------------------- ------ -サーバーバージョン5.0.77 / *!40101 SET @OLD_CHARACTER_SET_CLIENT = @@ CHARACTER_SET_CLIENT * /; / *!40101 SET @OLD_CHARACTER_SET_RESULTS = @@ CHARACTER_SET_RESULTS * /; / *!40101 SET @OLD_COLLATION_CONNECTION = @@ COLLATION_CONNECTION * /; / *!40101 SET NAMES utf8 * /; / *!40103 SET @OLD_TIME_ZONE = @@ TIME_ZONE * /; / *!40103 SET TIME_ZONE = '+ 00:00' * /; / *!40014 SET @OLD_UNIQUE_CHECKS = @@ UNIQUE_CHECKS、UNIQUE_CHECKS = 0 * /; / *!40014 SET @OLD_FOREIGN_KEY_CHECKS = @@ FOREIGN_KEY_CHECKS、FOREIGN_KEY_CHECKS = 0 * /; / *!40101 SET @OLD_SQL_MODE = @@ SQL_MODE、SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO' * /; / *!40111 SET @OLD_SQL_NOTES = @@ SQL_NOTES、SQL_NOTES = 0 * /; / *!40103 SET TIME_ZONE = @ OLD_TIME_ZONE * /; / *!40101 SET SQL_MODE = @ OLD_SQL_MODE * /; / *!40014 SET FOREIGN_KEY_CHECKS = @ OLD_FOREIGN_KEY_CHECKS * /; / *!40014 SET UNIQUE_CHECKS = @ OLD_UNIQUE_CHECKS * /; / *!40101 SET CHARACTER_SET_CLIENT = @ OLD_CHARACTER_SET_CLIENT * /; / *!40101 SET CHARACTER_SET_RESULTS = @ OLD_CHARACTER_SET_RESULTS * /; / *!40101 SET COLLATION_CONNECTION = @ OLD_COLLATION_CONNECTION * /; / *!40111 SET SQL_NOTES = @ OLD_SQL_NOTES * /;
mysqldumpは、mysql.time_zone_nameテーブルに書き込めないと誓うこともあります。
mysqldump: '/ *を実行できませんでした!40103 SET TIME_ZONE =' + 00:00 '* /':テーブル 'mysql.time_zone_name'は存在しません(1146)、これは--skip-tz-utcオプションによって解決されます
データ復旧
それでは、MySQLがデータベース情報を保存する方法についてもう少し詳しく見てみましょう。 MySQLの観点でのベースは、テーブル定義、インデックス、およびデータが格納されるディレクトリです(InnoDBの場合、テーブル定義のみがディレクトリに格納され、データは別のファイルに格納されます)。 MySQLがデータベースを見るために必要なことは、/ var / lib / mysql /内のディレクトリを見るだけです。
データベース内のテーブルとデータを取得するには、そこにあったすべてのファイルを復元する必要があります。
プロシージャと関数はメインデータベースには保存されませんが、procテーブルのmysqlデータベースにあります。したがって、このデータベースも復元する必要があります。
タスクは、mysqldプロセスが開始され、削除されたファイルの開いているファイル記述子を保持し、記述子が閉じるまでファイルを削除しないという事実によって促進されます。 / procファイルシステムは、/ proc / [pid] / fd / *のリンクを介してこれらのファイルへのアクセスを提供します
#ls -l / proc / 2544 / fd / 合計0 lr-x ------ 1ルートルート64 Jun 22 12:05 0-> / dev / null l-wx ------ 1 root root 64 Jun 22 12:05 1-> /var/log/mysqld.log lrwx ------ 1ルートルート64 6月22日12:05 10->ソケット:[9786] lrwx ------ 1ルートルート64 Jun 22 12:05 11-> / tmp / ibo0UVMZ(削除済み) lrwx ------ 1ルートルート64 Jun 22 12:05 12->ソケット:[9787] lrwx ------ 1 root root 64 Jun 22 12:05 13-> /var/lib/mysql/mysql/host.MYI(削除済み) ... lrwx ------ 1ルートルート64 Jun 22 12:05 28-> /var/lib/mysql/prod/table1.MYI(削除済み) lrwx ------ 1ルートルート64 Jun 22 12:05 29-> /var/lib/mysql/prod/table1.MYD(削除済み) ...
これを使用してデータベース名を見つけて復元し、/ var / lib / mysql /内のディレクトリのみをフィルタリングして、同じ場所に作成します。
#ls -l / proc / 2544 / fd / | grep / var / lib / mysql / | cut -d '' -f11 | cut -d / -f 5.6 | grep / | カット-d / -f1 | ソート-u mysql 製品 #ls -l / proc / 2544 / fd / | grep / var / lib / mysql / | cut -d '' -f11 | cut -d / -f 5.6 | grep / | カット-d / -f1 | sort -u | xargs -I {} mkdir -v / var / lib / mysql / {} mkdir:作成されたディレクトリ `/ var / lib / mysql / mysql ' mkdir:作成されたディレクトリ `/ var / lib / mysql / prod '
mysqlはベースを認識します:
mysql>データベースを表示します。 + -------------------- + | データベース| + -------------------- + | information_schema | | mysql | | 製品| + -------------------- + セット内の3行(0.00秒)
ただし、mysqldumpは引き続きvoidをエクスポートします。 修正を試み、プロセスによってまだ開いている残りのファイルを復元します。 これを行うには、/ var / lib / mysql /から/ procのファイルへのリンクを作成します。
#ls -l / proc / 2544 / fd / | grep / var / lib / mysql / | cut -d '' -f9,11 | awk '{cmd = "ln -s / proc / 2544 / fd /" $ 1 "" $ 2; print(cmd); system(cmd);}' ln -s / proc / 2544 / fd / 13 /var/lib/mysql/mysql/host.MYI ln -s / proc / 2544 / fd / 14 /var/lib/mysql/mysql/host.MYD ... ln -s / proc / 2544 / fd / 3 / var / lib / mysql / ibdata1 ... ln -s / proc / 2544 / fd / 38 /var/lib/mysql/prod/table1.MYD ln -s / proc / 2544 / fd / 9 / var / lib / mysql / ib_logfile1 ...
この操作の後、mysqldumpは引き続きvoidを返します。特定のテーブルをエクスポートするように要求すると、そのようなテーブルが存在しないことを誓います。
#mysqldump --protocol tcp --skip-tz-utc prod table2 mysqldump:テーブルが見つかりませんでした:「table2」 #mysql --protocol tcp mysql> prodを使用します。 データベースが変更されました mysql> show tables; 空のセット(0.00秒)
問題は、テーブル記述ファイルがプロセスによって常に開かれておらず、めったにアクセスされないため、前の手順でこれらのファイルを「復元」できないことです。 テーブルをエクスポートできるかどうかの決定は、テーブル記述ファイルに基づいて行われるため、自動エクスポートがクラッシュしました。
ただし、記述ファイルがなくても、テーブルからのデータの直接受信は妨げられません。
mysql> select count(*)from table1; + ---------- + | カウント(*)| + ---------- + | 100 | + ---------- + セット内の1行(0.00秒) mysql> select * from table1 limit 0.5; + ---- + ------------------------------------- + | id | v | + ---- + ------------------------------------- + | 1 | b026324c6904b2a9cb4b88d6d61c81d1-| | 2 | 26ab0db90d72e28ad0ba1e22ee510510-| | 3 | 6d7fce9fee471194aa8b5b6e47267f03-| | 4 | 48a24b70a0b376535542b996af517398-| | 5 | 1dcca23355272056f04fe8bf20edfce0-| + ---- + ------------------------------------- + セット内の5行(0.00秒) mysql> select * from table2 limit 0.5; + ---- + ------------------------------------- + | id | v | + ---- + ------------------------------------- + | 1 | b026324c6904b2a9cb4b88d6d61c81d1-| | 2 | 26ab0db90d72e28ad0ba1e22ee510510-| | 3 | 6d7fce9fee471194aa8b5b6e47267f03-| | 4 | 48a24b70a0b376535542b996af517398-| | 5 | 1dcca23355272056f04fe8bf20edfce0-| + ---- + ------------------------------------- + セット内の5行(0.00秒)
しかし、テーブルにはblobと複雑な構造があるため、データを取得するこのような方法は便利ではないようです。 また、InnoDBテーブルはデータベースのあるディレクトリに記述ファイルのみを保存するため、この手順では復元されません。したがって、メモリからすべてのテーブル名を知っている場合にのみ、それらからのフェッチが可能です。
後者の方法は、緊急時にいくつかの重要な情報を「保存」するのに役立ちます。
結論
この記事に記載されているデータベースを完全に復元する機能は動作しませんでした(無効になっています!)。
ネットワークの広大な全体にフラッシュする情報を回復する魔法の方法をすべて信頼しないでください。 バックアップを作成し、復旧計画を立て、修復不可能な事態が発生する前に、可能な復旧シナリオを常に確認してください。