MySQLでレプリケーション設定



##ポートを開ける
基本、マスタにて、スレーブからレプリケーション用のユーザーがログインできるようにしておけばよいみたい。

#####centos6.x

```bash
iptables -I INPUT -m state --state NEW -p tcp --dport 3306 -j ACCEPT
```
実際は-s オプションでスレーブのIPのみを許可した方がいいでしょう。

####centos7.x

```bash
firewall-cmd --permanent --add-port=3306/tcp
```

##ユーザーを作成する
レプリケーション用のユーザーを作成します。
mysqlのユーザーは'username'@'hostname'という形式なので、hostnameにも注意してユーザーを作成します。

```
 GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY 'password';
```
実際は'%'のところに、'192.168.0.100'というふうにスレーブのIPのみを指定した方がいいでしょう。
作成したら、スレーブから、マスタのDBにログインできるか確認しておきます。

```bash
mysql -h 192.168.0.100 -u repl -p
```

##実作業

###my.cnfの編集@マスター

my.cnfの[mysqld]パートに、下記を追加します。server-idは一意なものなら何でも。

```bash
[mysqld]

server-id=101
log-bin=mysql-bin
set-variable=expire_logs_days=7
```
設定したら再起動します。

* server-id レプリケーションに必要です。
* binlogファイルのprefix名となります。レプリケーションに限らずbinlog取得に必要。
* binlogの有効期限。適度に設定しておかないと空きスペースが無くなります。
	* 但し、7日キッチリに削除されるわけではない。再起動時や新規ファイル生成時など。

###my.cnfの編集@スレーブ

```bash
[mysqld]

server-id=102
read_only
```

* server-idはレプリケーションに必要。
* read_onlyは、特別権限？以外のユーザーでの更新を防止するため。

設定したら再起動します。

###データの取得と展開

####データの取得@マスター
テーブルをロックし、FileとPositionを確認します。
これは、スレーブがどこからレプリケーションを始めたらよいかの情報として使います。

#####メモ（追記）

```bash
mysqldump -u root -p --all-databases --master-data --single-transaction --flush-logs --events > all.sql
```
とすることで、以下に説明しているロック等をせずにデータを取得でき、かつ、

```bash
mysql -u root -p < all.sql
```
と、スレーブに展開することで後のプロセスにあるスレーブでのCHANGE MASTER TO〜も省けます（--master-dataオプションを付与することで、CHANGE MASTER TO〜分も包含されます）。

なお、--single-transactionはInnoDBじゃないと意味がないようです。

#####ロック

ロックします。この間、書込みはできません。

```bash
mysql> flush tables with read lock;
```

#####レプリケーション位置の確認

FileとPositionを確認します。

```bash
mysql> show master status;
```
とすると、

```bash
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      106 |              |                  |
+------------------+----------+--------------+------------------+
```
こんな感じのものが表示されるので、FileとPositionをメモしておきます。

>Empty set(0.00 sec)と表示された場合はFileは""、Positionは4にする。あるいは、masterの設定ができているか確認する。

#####データの取得

ロックしたので、実際にデータを取得します。私はDB単位で操作することが多いのでDBをしていしています。

```bash
mysqldump -u root -p testdb --lock-all-table > dump.sql
```
全体を取得する場合は、

```bash
mysqldump -u root -p --all-databases --lock-all-table --events> dump.sql
```

とします。--eventsはWarningが出たので入れました。

####ロックの解除
データの取得が完了したら、ロックを解除します。

```bash
mysql> unlock tables;
```

#####データのコピー

取得したdumpデータをスレーブにどうにかしてコピーします。私はscpでやりました。

####データの展開@スレーブ
スレーブにて、データを展開します。

```bash
mysql -u root -p testdb < dump.sql
```

###マスター情報の登録とレプリケーション開始@スレーブ

####マスター情報の登録

スレーブDBにて、マスターで取得したFile,Positionやレプリケーション用のユーザー情報等を設定するSQL文を実行します。

```bash
mysql > CHANGE MASTER TO
       MASTER_HOST='192.168.0.100',
       MASTER_USER='repl',
       MASTER_PASSWORD='password',
       MASTER_LOG_FILE='mysql-bin.000001',
       MASTER_LOG_POS=106;
```

####スレーブのスタート

```bash
mysql >start slave;
```

####状態確認

```bash
mysql> show slave status \G;
```
で(\Gは表示形式の変更)、

* Slave_IO_Running
* Slave_SQL_Running

がyesになっていることを確認。

##トラブル対応

###セットアップ時

####Slave_IO_Runningの発生
セットアップ時に、Slave_IO_Runningに遭遇しました。それぞれ状況が違います。

* マスタサーバーにつながらない
* binlogのバージョンのファイル名が合っていない

のいずれかでした。サーバ接続エラーの場合は、show slave statusの下の方にその旨表示されます。

###運用後

####サーバとスレーブの矛盾
何かしらの理由でサーバとスレーブに矛盾が発生したら、基本的に、初期状態と同じ操作をする。
つまり、

* マスターをロックして、データ出力（そしてロック解除）。
* スレーブで取り込み。
* change master to 〜で、File,Positionを設定。
* slave start

という流れ。

####ログファイルの肥大対応

MySQLにログイン出来ないほど肥大したら、/var/lib/mysql以下の古いbinlogファイルを削除する。
ログイン可能な状態だったり、復旧状態になったら、MySQLにログインして、

```bash
mysql >show master logs
```
でマスターが保持しているログを確認。
スレーブにログインして、念のため、

```bash
mysql >show slave status
```
で使用中のログを確認します。その後、マスターにて、

```bash
 purge master logs to 'mysqld-bin.000001';
```
などとすることで、過去ログが消えます（指定したものは保持され、それ以前が消えます）。

####RESET SLAVE

セットアップ時等に、設定がぐちゃぐちゃになって何をやったかわからなくなる場合がある。
そういう場合は、

```
reset slave
reset slave all
```
reset slaveもしくはallとすると、初期状態に戻ります。
設定で失敗した場合は、reset slaveとすればいいでしょう。表面上はログファイル名、Position、マスターへのログインID,PWがリセットされるようです。
その場合は、

```bash
CHANGE MASTER TO
       MASTER_USER='repl',
       MASTER_PASSWORD='password',
```
として、必要な箇所だけ更新して下さい。