【MariaDB】MariaDBにおけるレプリケーション環境構築方法

## はじめに
この記事ではMariaDBにおけるレプリケーション環境の構築方法についてまとめる。
レプリケーション自体の説明やどういうことに使うかといったことについては記載しない。

## この記事の対象者
- MariaDBにおけるレプリケーションの方法を知りたい方

## 筆者の環境

MariaDB v11.4.2 のDockerイメージを使って環境構築している。
同一のdocker networkにコンテナを2つ用意し、1つはマスタ、もう一つはレプリカとする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68663/98d644c8-9ac3-b07a-c5b1-d1d8103accae.png)

試した環境は以下のGitHubに上げておく。

https://github.com/TomoProg/experiments/tree/main/mariadb_replication

## 環境構築方法

### マスタ側の準備
マスタ側（レプリケーションの元となるDB）の準備を行う

#### MariaDBの設定
MariaDBの設定ファイル(`*.cnf`)に下記を設定する。

```
[mariadb]
log-bin
server_id=10
log-basename=master1
binlog-format=mixed
```

- **log-bin**

バイナリログを出力するかどうかを指定する。
レプリケーションにはバイナリログを使用するため、この設定は必須。
`log-bin=〇〇`みたいな書き方はせず、`log-bin`とだけ書けばOK。

- **server_id**

MariaDBサーバのIDを整数で指定する。
レプリケーションを構築するすべてのDBサーバ内で一意にする必要がある。

- **log-basename**

すべてのログ関連ファイルのベースとなる名前を指定する。
これを指定しないとファイル名にホスト名が使われ、ホスト名が変更されたときに影響があるため、設定しておくことを推奨している。

- **binlog-format**

バイナリログの書き方を指定する。
`row`, `statement`, `mixed`のいずれかを指定可能。
基本的には`mixed`を使えば問題ない。

`row`はバイナリログのファイルサイズが大きくなるが、個々の行がどのように変わるのかを記録するため、安全にレプリケーションできる。

`statement`はファイルサイズは小さいが、クエリそのものをバイナリログに書き込むため、非決定的なSQL（現在日時を使っているなど）の場合、マスタとレプリカで値が異なってしまう可能性がある。

`mixed`はそれらのいいとこどり。
基本的には`statement`を使い、非決定的なクエリの場合は`row`が使われる。

#### レプリケーションユーザの作成
レプリカがマスタのバイナリログを読み込めるように、レプリケーション専用のユーザを作成する。
`replication slave`の権限が必要になるため、その権限も付与しておく。

```sql
-- レプリケーション用のユーザ作成
create user if not exists 'repl'@'%' identified by '12345678';

-- replication slave の権限も付与する
grant replication slave on *.* to 'repl'@'%';
```

#### 全テーブルのロック
レプリケーション設定中にDBの変更が起きないようにすべてのテーブルをロックしておく。

```sql
FLUSH TABLES WITH READ LOCK
```

`FLUSH`ステートメントを入力したセッションを切ってしまうと、テーブルロックが解除されてしまうため、セッションを切らずに置いておくこと。

#### バイナリログのポジションの確認
`show master status`でバイナリログのファイル名（File列）とポジション（Position列）を確認し、メモしておく。

```sql
show master status;
```

```
+--------------------+----------+--------------+------------------+
| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| master1-bin.000002 |     1188 |              |                  |
+--------------------+----------+--------------+------------------+
```

#### DBのバックアップ

`mariadb-backup`コマンドでフルバックアップを取得する。
`target-dir`オプションでバックアップ先を指定可能。
```
mariadb-backup --backup --target-dir=/var/data/backup -uroot -p12345678
```

`target-dir`で指定したディレクトリごと、レプリカにコピーする。


### レプリカの準備

#### MariaDBの設定

MariaDBの設定ファイル(`*.cnf`)に下記を設定する。
レプリカ側は`server_id`のみを設定する。
マスタや他のレプリカと同じ`server_id`にならないように注意。

```
[mariadb]
server_id=20
```

#### バックアップのリストア

マスタ側で取得したバックアップをレプリカ側でリストアする。
MariaDBのデータディレクトリが空でないと、`mariadb-backup`コマンドの際に失敗してしまうため、データディレクトリの中身をすべて削除した状態にしておく。


```sh
# 隠しファイルを含めて、データディレクトリの中身を全部削除
# これをやっておかないとmariadb-backupコマンドの際にエラーになる
rm -rf /var/lib/mysql/* && rm -rf /var/lib/mysql/.*
```

```sh
# copy-backオプションを使うことでリストアできる
# target-dirにバックアップファイルのディレクトリを指定する
mariadb-backup --copy-back --target-dir=/var/data/backup/
```

#### データディレクトリの中身の所有者を変更する
`mariadb-backup`コマンドでリストアした場合、リストアされたデータディレクトリ内のファイルの所有者およびグループはコマンドを入力したユーザになるため、どちらも`mysql`に変更しておく。
```sh
chown -R mysql:mysql /var/lib/mysql/
```

#### レプリカのMariaDBを再起動する
dockerのMariaDBコンテナであれば、`docker restart`でOK
```
docker restart mariadb_slave
```

### マスタ側のテーブルロックを解除する
ここまで来れば、マスタ側のテーブルロックを解除して問題ない。
テーブルロック (`FLUSH TABLES WITH READ LOCK`) していたセッションを切るか、テーブルロックしているセッションで以下を入力すれば解除可能。

```sql
UNLOCK TABLES;
```

### どのサーバをマスタにするのか設定する

レプリカ側で`CHANGE MASTER TO`を使い、どのサーバをマスタとするか設定する。

```
CHANGE MASTER TO　
　　　　MASTER_HOST='mariadb_master',
  MASTER_USER='repl', 
  MASTER_PASSWORD='12345678', 
  MASTER_PORT=3306, 
  MASTER_LOG_FILE='master1-bin.000002', 
  MASTER_LOG_POS=1188, 
  MASTER_CONNECT_RETRY=10;
```


- **MASTER_HOST**

マスタとなるサーバのホスト名を入れる。

- **MASTER_USER**

マスタ側の設定で作成したレプリケーション用のユーザ

- **MASTER_PASSWORD**

レプリケーション用のユーザのログインパスワード

- **MASTER_PORT**

マスタとなるサーバのMariaDBのポート番号

- **MASTER_LOG_FILE**

マスタ側でバイナリログのポジションの確認(`show master status`)した際にメモしておいた、ログファイル名

- **MASTER_LOG_POS**

マスタ側でバイナリログのポジションの確認(`show master status`)した際にメモしておいた、ポジション

- **MASTER_CONNECT_RETRY**

マスタへの接続が失敗した際に何回リトライするか。

### レプリケーションを開始する
レプリカ側にて以下のステートメントを実行し、レプリケーションを開始する。

```
START SLAVE;
```

開始したら、`SHOW SLAVE STATUS` ステートメントを実行し、`Slave_IO_Running`、`Slave_SQL_Running`の状態を確認する。
これらが`Yes`になっていれば問題なし。
```
SHOW SLAVE STATUS \G
*************************** 1. row ***************************
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
```

何かしらのエラーが発生した場合は、`SHOW SLAVE STATUS`の結果の`Last_IO_Error`にエラー内容が設定されるため、ここをみて対処する。

## レプリケーションの確認
実際にレプリケーションができているか確認する。
マスタ、レプリカが以下のテーブルを持っている状態とする。

- **マスタ**
```
select * from t1;
+----+------+
| id | name |
+----+------+
|  1 | taro |
|  2 | jiro |
+----+------+
```

- **レプリカ**

```
select * from t1;
+----+------+
| id | name |
+----+------+
|  1 | taro |
|  2 | jiro |
+----+------+
```

この状態でマスタに対してデータを変更してみる。

```sql
-- マスタで実行する
update t1 set name = 'taro2' where id = 1;
```

レプリカ側がマスタ側と同じ状態になっていることを確認する。
```
select * from t1;
+----+-------+
| id | name  |
+----+-------+
|  1 | taro2 |
|  2 | jiro  |
+----+-------+
```


## まとめ
今回はMariaDBにおけるレプリケーションの環境構築方法をまとめた。
MariaDBでレプリケーション環境を整えようしている人に参考になれば嬉しく思う。

それではまた。
TomoProg

## 参考資料

https://mariadb.com/kb/en/replication-overview/

https://mariadb.com/kb/en/setting-up-replication/