ライブラリを削除して道を走らないで、MySQLデータの回復を詳しく理解します

53944 ワード

日常の仕事では、手ぶれ、条件の書き間違え、表名の書き間違え、生産ライブラリの誤接続によるライブラリ表とデータの誤削除が発生します.では、データさえ回復できなければ、DBAは何が必要ですか.
1はじめに
データ・リカバリの前提でバックアップを行い、binlogをrow形式で開きます.バックアップファイルがなければ、ライブラリテーブルを削除して本当に削除し、lsofに記録があれば、一部のファイルを復元する可能性があります.しかし、ちょうどデータベースがこのテーブルファイルを開いていない場合は、道を走るしかありません.binlogがオンになっていない場合は、データを復元した後、バックアップポイントからのデータがなくなります.binlogフォーマットがrowでない場合、データを誤って操作した後はフラッシュバック操作ができず、バックアップ・リカバリ・プロセスを正直に実行するしかありません.
2直接リカバリ
ダイレクト・リカバリは、バックアップ・ファイルを使用してフル・リカバリを行う最も一般的なシーンです.
2.1 mysqldumpバックアップフルリカバリ
mysqldumpファイルを使用してデータを復元するのは簡単で、実行を直接解凍しました.
gzip -d backup.sql.gz | mysql -u<user> -h<host> -P<port> -p

2.2 xtrabackupバックアップフルリカバリ
リカバリプロセス:
#    :  (             )
innobackupex --decompress 

#    :    
innobackupex --apply-log  

#    :           
innobackupex --datadir= --copy-back 

2.3ポイント・イン・タイム・リカバリに基づく
ポイント・ベースのリカバリはbinlogログに依存します.binlogからバックアップ・ポイントからリカバリ・ポイントまでのすべてのログを探して適用する必要があります.テストしてみましょう.
新しいテストテーブル:
chengqm-3306>>show create table mytest.mytest \G;
*************************** 1. row ***************************
Table: mytest
Create Table: CREATE TABLE `mytest` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ctime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

1秒あたり1つのデータを挿入:
[mysql@mysql-test ~]$ while true; do mysql -S /tmp/mysql.sock -e 'insert into mytest.mytest(ctime)values(now())';date;sleep 1;done

バックアップ:
[mysql@mysql-test ~]$ mysqldump --opt --single-transaction --master-data=2 --default-character-set=utf8 -S /tmp/mysql.sock -A > backup.sql

バックアップ時のログの場所を特定します.
[mysql@mysql-test ~]$ head -n 25 backup.sql | grep 'CHANGE MASTER TO MASTER_LOG_FILE'
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000032', MASTER_LOG_POS=39654;

2020-06-09 11:01:54という時点に復元すると仮定し、binlogから39654から2020-06-09 11:01:54までのログを検索します.
[mysql@mysql-test ~]$ mysqlbinlog --start-position=39654 --stop-datetime='2019-08-09 11:01:54' /data/mysql_log/mysql_test/mysql-bin.000032 > backup_inc.sql
[mysql@mysql-test-83 ~]$ tail -n 20 backup_inc.sql
......
### INSERT INTO `mytest`.`mytest`
### SET
###   @1=161 /* INT meta=0 nullable=0 is_null=0 */
###   @2='2020-06-09 11:01:53' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
......

現在のデータ・エントリ数:
-- 2020-06-09 11:01:54       
chengqm-3306>>select count(*) from mytest.mytest where ctime < '2020-06-09 11:01:54';
+----------+
| count(*) |
+----------+
|      61 |
+----------+
1 row in set (0.00 sec)

--       
chengqm-3306>>select count(*) from mytest.mytest;
+----------+
| count(*) |
+----------+
|      80 |
+----------+
1 row in set (0.00 sec)

次に、リカバリを実行します.
#     
[mysql@mysql-test ~]$ mysql -S /tmp/mysql.sock < backup.sql 

#       
[mysql@mysql-test ~]$ mysql -S /tmp/mysql.sock < backup_inc.sql

データの確認:
chengqm-3306>>select count(*) from mytest.mytest;
+----------+
| count(*) |
+----------+
|      61 |
+----------+
1 row in set (0.00 sec)

chengqm-3306>>select * from mytest.mytest order by id desc limit 5;
+-----+---------------------+
| id  | ctime               |
+-----+---------------------+
| 61 | 2020-06-09 11:01:53 |
| 60 | 2020-06-09 11:01:52 |
| 59 | 2020-06-09 11:01:51 |
| 58 | 2020-06-09 11:01:50 |
| 57 | 2020-06-09 11:01:49 |
+-----+---------------------+
5 rows in set (0.00 sec)

2020-06-09 11:01:54という時点に回復しました.
3テーブルを復元
3.1 mysqldumpバックアップからテーブルをリカバリ
リカバリするテーブルがmytestだと仮定します.mytest:
#           
sed -n '/^-- Current Database: `mytest`/,/^-- Current Database:/p' backup.sql > backup_mytest.sql

#              
sed -e'/./{H;$!d;}' -e 'x;/CREATE TABLE `mytest`/!d;q' backup_mytest.sql > mytest_table_create.sql

#                
grep -i 'INSERT INTO `mytest`' backup_mytest.sql > mytest_table_insert.sql

#        mytest  
mysql -u<user> -p mytest < mytest_table_create.sql

#        mytest.mytest  
mysql -u<user> -p mytest <  mytest_table_insert.sql

3.2 xtrabackupバックアップからテーブルをリカバリ
仮定./backup_xtra_fullディレクトリは、解凍後にログを適用したバックアップファイルです.
3.2.1 MyISAM表
バックアップファイルからテーブルをリカバリするとします.t_myisam.バックアップファイルからt_を見つけるmyisam.frm, t_myisam.MYD, t_myisam.MYIの3つのファイルは、対応するデータディレクトリにコピーされ、MySQLへのアクセスを許可されます.表情をチェック:
chengqm-3306>>show tables;
+------------------+
| Tables_in_mytest |
+------------------+
| mytest           |
| t_myisam         |
+------------------+
2 rows in set (0.00 sec)

chengqm-3306>>check table t_myisam;
+-----------------+-------+----------+----------+
| Table           | Op    | Msg_type | Msg_text |
+-----------------+-------+----------+----------+
| mytest.t_myisam | check | status   | OK       |
+-----------------+-------+----------+----------+
1 row in set (0.00 sec)

3.2.2 Innodb表
バックアップファイルからテーブルをリカバリするとします.t_innodb、リカバリの前提はinnodb_が設定されていることです.file_per_table = on:
  • から新しいインスタンスが始まります.
  • インスタンスに元と同じテーブルを作成します.
  • alter table t_を実行するinnodb discard tablespace; 表領域を削除すると、この操作でt_innodb.ibd削除;
  • バックアップファイルからt_を検索innodb.ibdというファイルは、対応するデータディレクトリにコピーし、許可します.
  • alter table t_を実行するinnodb IMPORT tablespace; 表領域のロード;
  • flush table t_を実行するinnodb;check table t_innodb; チェックリスト;
  • mysqldumpを使用してデータをエクスポートし、リカバリするデータベースにインポートします.

  • 注意:
  • が新しいインスタンスで再dumpを復元するのは、リスクを回避するためであり、テストであれば、元のライブラリで手順2-6を直接操作することができる.
  • は8.0以前のバージョンでのみ有効です.

  • 4ジャンプ誤操作SQL
    誤操作をスキップSQLは、drop tabledatabaseなどのフラッシュバックできない操作を実行するために一般的に使用されます.
    4.1バックアップ・ファイル・リカバリによるスキップ
    4.1.1 GTIDを開かない
    バックアップ・ファイルを使用してリカバリする手順と、複数のbinlogを検索する操作とは異なり、ポイント・イン・タイム・リカバリに基づく操作の差は多くありません.例を挙げると、私はここで2つのテーブルaとbを創立して、毎分1本のデータを挿入して、それから全量のバックアップをして、更にテーブルbを削除して、今このSQLをスキップします.
    テーブルbを削除した後のデータベースの状態:
    chgnqm-3306>>show tables;
    +------------------+
    | Tables_in_mytest |
    +------------------+
    | a                |
    +------------------+
    1 row in set (0.00 sec)
    

    1.バックアップ時のログの場所を特定
    [mysql@mysql-test ~]$ head -n 25 backup.sql | grep 'CHANGE MASTER TO MASTER_LOG_FILE'
    -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000034', MASTER_LOG_POS=38414;
    

    2.drop table文を実行したposの位置を特定する
    [mysql@mysql-test mysql_test]$  mysqlbinlog -vv /data/mysql_log/mysql_test/mysql-bin.000034 | grep -i -B 3 'drop table `b`';
    # at 120629
    #200618 19:48:30 server id 83  end_log_pos 120747 CRC32 0x6dd6ab2a     Query    thread_id=29488    exec_time=0    error_code=0
    SET TIMESTAMP=1566128910/*!*/;
    DROP TABLE `b` /* generated by server */
    

    結果からdropが存在する文の開始位置は120629であり,終了位置は120747であることが分かる.
    3.binglogからこの文をスキップした他のレコードを抽出する
    #      start-position        pos   ,stop-position   drop        
    mysqlbinlog -vv --start-position=38414 --stop-position=120629 /data/mysql_log/mysql_test/mysql-bin.000034 > backup_inc_1.sql
    
    #      start-position   drop        
    mysqlbinlog -vv --start-position=120747 /data/mysql_log/mysql_test/mysql-bin.000034 > backup_inc_2.sql
    

    4.バックアップファイルの復元
    [mysql@mysql-test ~]$ mysql -S /tmp/mysql.sock < backup.sql
    
           :
    
    chgnqm-3306>>show tables;
    +------------------+
    | Tables_in_mytest |
    +------------------+
    | a                |
    | b                |
    +------------------+
    2 rows in set (0.00 sec)
    
    chgnqm-3306>>select count(*) from a;
    +----------+
    | count(*) |
    +----------+
    |       71 |
    +----------+
    1 row in set (0.00 sec)
    

    5.増分データの復元
    [mysql@mysql-test ~]$ mysql -S /tmp/mysql.sock < backup_inc_1.sql
    [mysql@mysql-test ~]$ mysql -S /tmp/mysql.sock < backup_inc_2.sql
    

    リカバリ後のステータスは、drop文がスキップされていることがわかります.
    chgnqm-3306>>show tables;
    +------------------+
    | Tables_in_mytest |
    +------------------+
    | a                |
    | b                |
    +------------------+
    2 rows in set (0.00 sec)
    
    chgnqm-3306>>select count(*) from a;
    +----------+
    | count(*) |
    +----------+
    |      274 |
    +----------+
    1 row in set (0.00 sec)
    

    4.1.2 GTIDを開く
    GTIDを使用すると、エラーのSQLを直接スキップできます.
  • バックアップ時のログの場所を特定します.
  • drop table文を実行したGTID値を探し出す.
  • バックアップ時のログ位置を最新のbinglogログにエクスポートします.
  • バックアップファイルを復元します.
  • はこのGTIDをスキップした.
  • SET SESSION GTID_NEXT='    GTID  ';
    BEGIN; COMMIT;
    SET SESSION GTID_NEXT = AUTOMATIC;
    
  • は、ステップ3で得られたインクリメンタルbinlogログを適用する.

  • 4.2遅延ライブラリを使用してスキップ
    4.2.1 GTIDを開かない
    遅延ライブラリリカバリを使用する重要な操作はstart slave untilです.私はテスト環境で2つのMySQLノードを構築して、ノード2は600秒遅延して、a、bの2つのテーブルを新築して、毎秒1本のデータシミュレーション業務データの挿入を挿入します.
    localhost:3306 -> localhost:3307(delay 600)
    

    現在のノード2の状態:
    chengqm-3307>>show slave status \G;
    ...
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000039
              Read_Master_Log_Pos: 15524
                   Relay_Log_File: mysql-relay-bin.000002
                    Relay_Log_Pos: 22845
            Relay_Master_Log_File: mysql-bin.000038
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
    ...
            Seconds_Behind_Master: 600
    ...
    

    現在のノードの2つのテーブル:
    chengqm-3307>>show tables;
    +------------------+
    | Tables_in_mytest |
    +------------------+
    | a                |
    | b                |
    +------------------+
    

    ノードでテーブルbを削除する:
    chengqm-3306>>drop table b;
    Query OK, 0 rows affected (0.00 sec)
    
    chengqm-3306>>show tables;
    +------------------+
    | Tables_in_mytest |
    +------------------+
    | a                |
    +------------------+
    1 row in set (0.00 sec)
    

    次に、このSQLの操作手順をスキップします.
    1.遅延ライブラリ同期停止
    stop slave;
    

    2.drop table文を実行した前の文のpos位置を見つける
    [mysql@mysql-test ~]$ mysqlbinlog -vv /data/mysql_log/mysql_test/mysql-bin.000039 | grep -i -B 10 'drop table `b`';
    ...
    # at 35134
    #190819 11:40:25 server id 83  end_log_pos 35199 CRC32 0x02771167     Anonymous_GTID    last_committed=132    sequence_number=133    rbr_only=no
    SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
    # at 35199
    #190819 11:40:25 server id 83  end_log_pos 35317 CRC32 0x50a018aa     Query    thread_id=37155    exec_time=0    error_code=0
    use `mytest`/*!*/;
    SET TIMESTAMP=1566186025/*!*/;
    DROP TABLE `b` /* generated by server */
    

    結果からdropが存在する文の前の文の開始位置が35134であることがわかり、35134に同期しました(これは間違っていません).
    3.遅延ライブラリをスキップするSQLの前の項目に同期する
    change master to master_delay=0;
    start slave until master_log_file='mysql-bin.000039',master_log_pos=35134;
    

    ステータスを表示すると、対応するノードに同期されています.
    chengqm-3307>>show slave status \G;
    ...
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000039
              Read_Master_Log_Pos: 65792
    ...
                 Slave_IO_Running: Yes
                Slave_SQL_Running: No
              Exec_Master_Log_Pos: 35134
    ...
                   Until_Log_File: mysql-bin.000039
                    Until_Log_Pos: 35134
    

    4.SQLをスキップして同期を開始
    set global sql_slave_skip_counter=1;
    start slave;
    

    同期状態を表示し、テーブルbを削除する文はスキップされました.
    chengqm-3307>>show slave status \G;
    ...
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
    ...
    1 row in set (0.00 sec)
    
    chengqm-3307>>show tables;
    +------------------+
    | Tables_in_mytest |
    +------------------+
    | a                |
    | b                |
    +------------------+
    2 rows in set (0.00 sec)
    

    4.2.2 GTIDを開く
    GTIDを使用してスキップする手順は簡単で、スキップするSQLのGTIDと同じトランザクションを実行すればスキップできます.
  • 同期を停止します.
  • drop table文を実行したGTIDを探し出す.
  • はこのGTIDの事務を実行する.
  • SET SESSION GTID_NEXT='    GTID  ';
    BEGIN; COMMIT;
    SET SESSION GTID_NEXT = AUTOMATIC;
    
  • 同期を継続します.
  • フラッシュバック.

  • フラッシュバック操作は逆操作であり、例えばdelete from a where id=1を実行すると、フラッシュバックは対応する挿入操作**insert into a(id,...)values(1,...)を実行し、**はデータを誤操作するために使用され、DML文にのみ有効であり、binlogフォーマットをROWにすることが要求される.この章では、使いやすいオープンソースツールを2つ紹介します.
    5.1 binlog2sql
    binlog 2 sqlは大衆評価オープンソースのbinlogを解析するためのツールであり、フラッシュバック文、プロジェクトアドレスbinlog 2 sqlを生成するために使用することができる.
    5.1.1インストール
    wget https://github.com/danfengcao/binlog2sql/archive/master.zip -O binlog2sql.zip
    unzip binlog2sql.zip
    cd binlog2sql-master/
    
    #     
    pip install -r requirements.txt
    

    5.1.2ロールバックSQLの生成
    python binlog2sql/binlog2sql.py --flashback \
    -h<host> -P<port> -u<user> -p'' -d<dbname> -t<table_name>\
    --start-file='' \
    --start-datetime='' \
    --stop-datetime='' > ./flashback.sql
    
    python binlog2sql/binlog2sql.py --flashback \
    -h<host> -P<port> -u<user> -p'' -d<dbname> -t<table_name> \
    --start-file='' \
    --start-position= \
    --stop-position= > ./flashback.sql
    

    5.2 MyFlash
    MyFlashは、美団評価会社の技術工程部が開発・維持しているDML操作をロールバックするツールで、プロジェクトリンクMyFlashです.
    制限:
  • binlogフォーマットはrowで、binlog_row_image=full;
  • は5.6と5.7しかサポートしていません.
  • はDML(追加、削除、変更)のみをロールバックできます.

  • 5.2.1インストール
    #   (centos)
    yum install gcc*  pkg-config glib2 libgnomeui-devel -y
    
    #     
    wget https://github.com/Meituan-Dianping/MyFlash/archive/master.zip -O MyFlash.zip
    unzip MyFlash.zip
    cd MyFlash-master
    
    #     
    gcc -w  `pkg-config --cflags --libs glib-2.0` source/binlogParseGlib.c  -o binary/flashback
    mv binary /usr/local/MyFlash
    ln -s /usr/local/MyFlash/flashback /usr/bin/flashback
    

    5.2.2使用
    ロールバック文を生成するには、次の手順に従います.
    flashback --databaseNames= --binlogFileNames= --start-position= --stop-position= 
    

    実行するとbinlog_が生成されますoutput_base.Flashbackファイルはmysqlbinlogで解析してから使用する必要があります.
    mysqlbinlog -vv binlog_output_base.flashback | mysql -u<user> -p