omoonのブログ

旅の思い出を写真とともに書いてみるか。

レプリケーションの復旧

サーバの構成

  • マスタ1台
  • スレーブ3台
  • バージョンはいずれも4.0系
mst(192.168.1.1) --+-- slv1(192.168.1.101)
                   |
                   +-- slv2(192.168.1.102)
                   |
                   +-- slv3(192.168.1.103)

状況

  • スレーブのうち1台(slv2)に誤って更新系クエリを発行。以降正常にレプリケーションが行われなくなっていた。
mst(192.168.1.1) --+-- slv1(192.168.1.101)
                   |
                   +-- slv2(192.168.1.102) <-- これがエラー
                   |
                   +-- slv3(192.168.1.103)
  • データサイズはtarでアーカイブして約12GB。アーカイブ化とコピーに30分以上かかってしまう。
  • サービスは思いっきり稼働中のため、スナップショットをとる際のmst上のロックは許されない。

方針

  • 正常なサーバslv1のレプリケーションをストップ
  • その時点でのマスタのバイナリログの位置情報を確認
  • slv1のデータをスナップショットとしてslv2にコピー
  • バイナリログ、位置情報をセットして、slv2でスレーブの開始

これで、サービスはいっさい停止することなく復旧が可能なのでは。ということでやってみる。

手順

正常に動いているスレーブのうち1台(slv1)のレプリケーションを止める。

mysql> stop slave;

show slave statusで、Master_Log_FileとExec_master_log_posを記録。
下記の例では、Read_Master_Log_Posの値とExec_master_log_posの値が違うが、実行されているのはExec_master_log_posまでとなるので、後でスレーブを開始する際に指定する値は、Exec_master_log_posの方となる。

mysql> show slave statu?G
*************************** 1. row ***************************
          Master_Host: 192.168.1.1
          Master_User: xxxx
          Master_Port: 3306
        Connect_retry: 60
      Master_Log_File: mst.041 <-- このファイル名と
  Read_Master_Log_Pos: 848194201
       Relay_Log_File: slv1-relay-bin.421
        Relay_Log_Pos: 4629877
Relay_Master_Log_File: mst.041
     Slave_IO_Running: No
    Slave_SQL_Running: No
      Replicate_do_db: 
  Replicate_ignore_db: 
           Last_errno: 0
           Last_error: 
         Skip_counter: 0
  Exec_master_log_pos: 848001448 <-- この位置を記録しておく
      Relay_log_space: 4822630
1 row in set (0.00 sec)

続いて、slv1のデータをtarでアーカイブ化。

# cd /usr/local/mysql/var
# tar cpf /var/tmp/mysql-snapshot.tar .

slv2にコピー。

# scp /var/tmp/mysql-snapshot.tar slv2:/var/tmp/

slv2でmysql停止。

# /etc/init.d/mysqld stop

slv2のデータフォルダ内のファイル全部削除

# cd /usr/local/mysql/var
# rm -rf *

コピーしたslv1のスナップショットをデータフォルダに展開

# tar xpf /var/tmp/mysql-snapshot.tar

データ以外の不要なファイル削除

# rm slv1*
# rm slv1*
# rm *pid
# rm *info

mysql起動

# /etc/init.d/mysqld start

mysqlに接続して、先ほどslv1上で記録したMaster_Log_FileとExec_master_log_posの値を設定。

# /usr/local/mysql/bin/mysql -u hoge -p
mysql>show slave status?G
mysql> CHANGE MASTER TO
    -> MASTER_LOG_FILE = 'mst.041',
    -> MASTER_LOG_POS = 848001448;
Query OK, 0 rows affected (0.01 sec)

スレーブを開始。

mysql> start slave;
mysql> show slave status?G
*************************** 1. row ***************************
          Master_Host: 192.168.1.1
          Master_User: xxxx
          Master_Port: 3306
        Connect_retry: 60
      Master_Log_File: mst.041
  Read_Master_Log_Pos: 851145455
       Relay_Log_File: slv2-relay-bin.001
        Relay_Log_Pos: 1578106
Relay_Master_Log_File: mst.041
     Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
      Replicate_do_db: 
  Replicate_ignore_db: 
           Last_errno: 0
           Last_error: 
         Skip_counter: 0
  Exec_master_log_pos: 849579516
      Relay_log_space: 3144045
1 row in set (0.00 sec)

おおー、できたよ。
後は、Exec_master_log_posがRead_Master_Log_Posに追いつくのを待ってOK。5分ぐらいで追いついた。
ちゃんとレプリケーションが復旧できましたとさ。

参考にしたもの

書籍

MySQL全機能リファレンス

MySQL全機能リファレンス

現場で使える MySQL (DB Magazine SELECTION)

現場で使える MySQL (DB Magazine SELECTION)