2013年5月23日木曜日

MySQLマスター手動切替

DB01(マスター)/DB02(スレーブ)の2台構成に

DB03を追加して

DB03(マスター)/DB02(スレーブ)の2台構成に切替を行います。(DB01はサーバ停止)


1.まずはDB03にmysqlをインストールして、DB03を一旦スレーブで起動させデータの同期を行います。

1.1.mysqlをインストールする[DB03]
インストール手順はこちらを参考
レプリケーション設定(非同期レプリケーション)
準同期レプリケーション設定

1.2./etc/my.cnfを設定する[DB03]
# vi /etc/my.cnf
基本的にはDB02(スレーブ)の/etc/my.cnfをコピーして、server-id=XXの箇所を、DB01(マスター)/DB02(スレーブ)と重複しない値に変更するだけ。

1.3.mysqlを再起動する[DB03]
# service mysqld restart

1.4.DB01(マスター)側でDB03のレプリケーション用ユーザを追加する[DB01]
# mysql -u root
mysql> SELECT user, host, password FROM mysql.user;
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO '★レプリケーション用ユーザ'@'★DB03のIP' IDENTIFIED BY '★パスワード';
mysql> FLUSH PRIVILEGES;

1.5.DBをダンプする[DB01]
# mysqldump -u root -p --all-databases --master-data=2 --single-transaction > /var/tmp/dump_20130523_01.sql

1.6.DB01からDB03へダンプファイルを転送する[DB01]
# scp /var/tmp/dump_20130523_01.sql ★DB03のアカウント@★DB03のIP:/var/tmp/

1.7.ダンプファイルをインポートする[DB03]
# mysql -u root -p < /var/tmp/dump_20130523_01.sql

1.8.ダンプファイルからステータス(ファイル名、ポジション)を取得する[DB03]
# head -100 /var/tmp/dump_20130523_01.sql | grep CHANGE
-- CHANGE MASTER TO MASTER_LOG_FILE='★ログファイル名', MASTER_LOG_POS=★ポジション;

1.9.パラメータを設定する[DB03]
# mysql -u root
mysql> CHANGE MASTER TO
    -> MASTER_HOST='★DB01マスターのIP',
    -> MASTER_USER='★レプリケーション用ユーザ',
    -> MASTER_PASSWORD='★パスワード',
    -> MASTER_PORT=3306,
    -> MASTER_LOG_FILE='★ログファイル名',
    -> MASTER_LOG_POS=★ポジション,
    -> MASTER_CONNECT_RETRY=10;

1.10.スレーブで起動する[DB03]
# mysql -u root
mysql> START SLAVE;

mysql> SHOW SLAVE STATUS\G・・・起動確認
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

1.11.DB03からDB01(マスター)へレプリケーションの接続ができるか確認する[DB03]
# mysql -u ★レプリケーション用ユーザ -p -h '★DB01のIP'

1.12.WEBサーバからDB03へ接続ができるか確認する[WEBサーバ]
# mysql -u ★WEBサーバからの接続用ユーザ -p -h '★DB03のIP'

※上記が接続できず、下記のエラーになりました。・・・
ERROR 1045 (28000): Access denied for user '★WEBサーバからの接続用ユーザ'@'★DB03のIP' (using password: NO)

※まずはiptablesを設定してみる[DB03]・・・
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 3306 -j ACCEPT

※現象が変わらないためユーザ権限を確認してみると[DB03]・・・
# mysql -u root
mysql> SELECT user, host, password FROM mysql.user;
マスターからmysql.userを丸ごとコピーしているのでユーザは存在する。

ただし、SHOW GRANTSで実際にユーザ権限を確認しようとすると・・・
mysql> SHOW GRANTS FOR ★WEBサーバからの接続用ユーザ@'★WEBサーバのIP';
ERROR 1141 (42000): There is no such grant defined for user '★WEBサーバからの接続用ユーザ' on host '★WEBサーバのIP'
エラーになる。WEBサーバからの接続用ユーザの定義がないとのこと??・・・

なので、
mysql> FLUSH PRIVILEGES;
を実行し、内部キャッシュを消去したら・・・
接続できました[DB03]

これで、第一段階の
DB01(マスター)/DB02(スレーブ)/DB03(スレーブ)
の3台構成になりました。


2.続いてマスター切替

2.1.サイトをメンテナンス中にするなどしてinsert/updateを停止する

2.2.insert/updateの停止確認(ステータス情報をリアルタイムで表示しておく)

[DB01]
# watch -n1 'mysql -uroot -e"SHOW MASTER STATUS\G"'
Position: XXXXXXXX

[DB02]
# watch -n1 'mysql -uroot -e"SHOW SLAVE STATUS\G"'
Read_Master_Log_Pos: XXXXXXXX

[DB03]
# watch -n1 'mysql -uroot -e"SHOW SLAVE STATUS\G"'
Read_Master_Log_Pos: XXXXXXXX

※insert/updateが停止されていれば、上記のポジションの値は変化しない。

2.3.上記のポジションの値と合わせて、プロセスが実行されていないことを確認する

[DB01]
mysql> SHOW FULL PROCESSLIST;

[DB02]
mysql> SHOW FULL PROCESSLIST;

[DB03]
mysql> SHOW FULL PROCESSLIST;

※何度か実行して確認する。

2.4.DB01のテーブルをロックし、DB02/DB03のスレーブ停止を行う
※ロック中に仮にinsert/updateがあった場合、プロセスが溜まっていってしまうので、下記の一連の作業は続けて行うこと。またロック以降のinsert/updateのデータは、マスター切替後、消滅します。

DB01のテーブルをロックする[DB01]
# mysql -u root
mysql> FLUSH TABLES WITH READ LOCK;

DB02とDB03のポジションの値(SHOW SLAVE STATUS\Gの値)が一致していることを確認する[DB02/DB03]

InnoDB内部状態を確認する[DB02]
# mysql -u root
mysql> SHOW ENGINE INNODB STATUS\G
Log sequence number XXXXXXXXXXXX・・・3つが同値か確認する
Log flushed up to   XXXXXXXXXXXX・・・3つが同値か確認する
Last checkpoint at  XXXXXXXXXXXX・・・3つが同値か確認する

InnoDB内部状態を確認する[DB03]
# mysql -u root
mysql> SHOW ENGINE INNODB STATUS\G
Log sequence number XXXXXXXXXXXX・・・3つが同値か確認する
Log flushed up to   XXXXXXXXXXXX・・・3つが同値か確認する
Last checkpoint at  XXXXXXXXXXXX・・・3つが同値か確認する

※DB02とDB03のポジションの値(SHOW SLAVE STATUS\Gの値)が一致していること、それぞれのサーバのSHOW ENGINE INNODB STATUS\Gの3つの値が必ず一致している状態でスレーブを停止すること!

スレーブ停止[DB02]
mysql> STOP SLAVE;

スレーブ停止[DB03]
mysql> STOP SLAVE;

DB01(マスター)で、mysqlの接続を切断する(ロック解除)
mysql> Ctrl-C -- exit!


2.5.念のため、バイナリファイルをディレクトリごとバックアップする[DB02]
# cp -rp /var/lib/mysql /var/lib/mysql.20130522

2.6.念のため、バイナリファイルをディレクトリごとバックアップする[DB03]
# cp -rp /var/lib/mysql /var/lib/mysql.20130522


2.7.my.cnf をマスター用に修正する[DB03]
# ls -lat /etc/my.cnf*
# cp -rp /etc/my.cnf /etc/my.cnf.20130522
# ls -lat /etc/my.cnf*
# vi /etc/my.cnf ・・・マスター用に変更
基本的にはDB01(マスター)の/etc/my.cnfをコピーして、server-id=XXの箇所を、DB02(スレーブ)と重複しない値に変更するだけ。(※マスター用my.cnfファイルを事前に準備しておくと良い)

※ファイルサイズが大きいため少し時間が掛かる

2.8.ポジションリセット[DB03]
# mysql -u root
mysql> RESET MASTER;・・・こっちは元々バイナリファイルが無くてエラーになったので不要でした
mysql> RESET SLAVE;

2.9.MySQL再起動[DB03]
# service mysqld restart

2.10.MySQLマスター起動確認[DB03]
# mysql -u root
mysql> SHOW MASTER STATUS;


2.11.ポジションリセット[DB02]
# mysql -u root
mysql> RESET MASTER;・・・こっちは元々バイナリファイルが無くてエラーになったので不要でした
mysql> RESET SLAVE;

2.12.MySQL再起動[DB02]
# service mysqld restart


2.13.マスターのステータス(ファイル名、ポジション)を取得する[DB03]
# mysql -u root
mysql> SHOW MASTER STATUS;
+----------------+----------+--------------+------------------+
| File           | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------+----------+--------------+------------------+
| ★ログファイル名 |★ポジション |              |                  |
+----------------+----------+--------------+------------------+

2.14.上記で取得したファイル名、ポジションでパラメータを設定する[DB02]
# mysql -u root
mysql> CHANGE MASTER TO
    -> MASTER_HOST='★DB03マスターのIP',
    -> MASTER_USER='★レプリケーション用ユーザ',
    -> MASTER_PASSWORD='★パスワード',
    -> MASTER_PORT=3306,
    -> MASTER_LOG_FILE='★ログファイル名',
    -> MASTER_LOG_POS=★ポジション,
    -> MASTER_CONNECT_RETRY=10;

2.14.スレーブで起動する[DB02]
mysql> START SLAVE;

mysql> SHOW SLAVE STATUS\G・・・起動確認
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

※パラメータの設定を下記の3つだけで実行したところ
Master_Userなどが空欄のままでSTART SLAVEを実行してしまい
Last_IO_Error: error connecting to master '@★DB03のIP:3306' - retry-time: 60 retries: 86400
エラーになりました。
手を抜かず全パラメータを設定しないといけないんですね・・・

mysql> CHANGE MASTER TO
    -> MASTER_HOST='★DB03マスターのIP',
    -> MASTER_LOG_FILE='★ログファイル名',
    -> MASTER_LOG_POS=★ポジション;

mysql> START SLAVE;

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Connecting to master
                  Master_Host: ★DB03のIP
                  Master_User:
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: ★ログファイル名
          Read_Master_Log_Pos: 107
               Relay_Log_File: mysqld-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: ★ログファイル名
             Slave_IO_Running: Connecting
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 107
              Relay_Log_Space: 107
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 1045
                Last_IO_Error: error connecting to master '@★DB03のIP:3306' - retry-time: 60  retries: 86400
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 0
1 row in set (0.00 sec)


これで
DB01(スタンドアローン)/DB02(スレーブ)/DB03(マスター)
の3台構成になりました。


3.1.あとは旧マスターを停止するだけ[DB01]
# service mysqld stop

3.2.バイナリファイル削除[DB02/DB03]

正しく切替ができたら、上記2.5./2.6.でバックアップした/var/lib/mysql.20130522を削除する


参考URL


0 件のコメント:

コメントを投稿