MariaDB冗長構成構築

#はじめに
何とかして冗長化構成のRDBがほしい、と調べた結果、MariaDBであれば実現できそうだったので構築内容を記した内容です。
2017年ごろの古いノウハウのサルベージです。

古いサルベージだけど、いい内容が書いてあるのか、結構ストックされます。
恥ずかしがらずにLGTMしてください！

#なぜMariaDBなのか
※galera clusterは、奇数ノードで構成しないとスプリットブレインを起こすとご指摘頂きました。
この手順では二台の偶数構成となっているため、クリティカルな環境には使用しないようお願いいたします。
ご指摘ありがとうございます。

MariaDBのマニュアルは非常に見づらくて、当初はMySQLを使用して構築しようとしていました。
ですが、MySQLはマスター/スレーブ構成であることがわかり、さらにコントローラーノードが必要であることがわかりました。
コントローラーを準備すると、奇数台構成になり、構築先の仮想環境が偶数台でリソース配分のミスマッチや管理上のミスマッチがありました。
また、コントローラーを冗長化しないと単一障害点となることになります。
結果、MariaDBで構築することにしました。

# 冗長構成
MariaDBだとマルチマスタ構成で構築でき、標準ではrsyncを使用して同期をとるようです。
DBへのアクセスポイント(VIP)については、keepalivedによりVIPを付与する構成としました。

#構築手順
##MariaDB
###構築と簡単なテスト
- リソース制約を緩和する。

```
vi /etc/security/limits.conf
*                -       nofile          16384
```

- swapを無効化する。

```
vi /etc/sysctl.conf
vm.swappiness = 0
```

- yumリポジトリを追加する。

```
vi /etc/yum.repo.d/MariaDB.repo
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.1/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
```

※「vi /etc/yum.repos.d/MariaDB.repo」かも
- MariaDBをインストールする。

```
yum install MariaDB-server MariaDB-client
```

- galera clusterを設定する。(1号機の内容)

```
cp -p /etc/my.cnf.d/server.cnf /etc/my.cnf.d/server.cnf.YYYYMMDD
vi /etc/my.cnf.d/server.cnf
diff /etc/my.cnf.d/server.cnf /etc/my.cnf.d/server.cnf.YYYYMMDD
19,29c19,24
< wsrep_on=ON
< wsrep_provider=/usr/lib64/galera/libgalera_smm.so
< wsrep_cluster_address=gcomm://
< binlog_format=row
< default_storage_engine=InnoDB
< innodb_autoinc_lock_mode=2
<
< wsrep_cluster_name=DBCLUSTER
< wsrep_node_name=<1号機のホスト名>
< wsrep_node_address=<1号機のIPアドレス>
<
---
> #wsrep_on=ON
> #wsrep_provider=
> #wsrep_cluster_address=
> #binlog_format=row
> #default_storage_engine=InnoDB
> #innodb_autoinc_lock_mode=2
```

- galera clusterを設定する。(2号機の内容)

```
cp -p /etc/my.cnf.d/server.cnf /etc/my.cnf.d/server.cnf.YYYYMMDD
vi /etc/my.cnf.d/server.cnf
diff /etc/my.cnf.d/server.cnf /etc/my.cnf.d/server.cnf.YYYYMMDD
19,29c19,24
< wsrep_on=ON
< wsrep_provider=/usr/lib64/galera/libgalera_smm.so
< wsrep_cluster_address=gcomm://<1号機のIPアドレス>
< binlog_format=row
< default_storage_engine=InnoDB
< innodb_autoinc_lock_mode=2
<
< wsrep_cluster_name=DBCLUSTER
< wsrep_node_name=<2号機のホスト名>
< wsrep_node_address=<2号機のIPアドレス>
<
---
> #wsrep_on=ON
> #wsrep_provider=
> #wsrep_cluster_address=
> #binlog_format=row
> #default_storage_engine=InnoDB
> #innodb_autoinc_lock_mode=2
```

- ファイアウォールに穴を開ける。もう少しノードを絞ったりしたほうがよさそう。

```
 firewall-cmd --add-port=3306/tcp --add-port=4567/tcp --add-port=4444/tcp --permanent
 firewall-cmd --reload
```

- SELINUXを有効にするとすごく複雑そうなので断念して無効に…。

```
vi /etc/selinux/config
```

- 文字コードをutf8に設定

```
cp -p /etc/my.cnf /etc/my.cnf.YYYYMMDD
vi /etc/my.cnf
diff /etc/my.cnf /etc/my.cnf.YYYYMMDD
10d9
< character-set-server=utf8
```

- mariadbの起動

```
systemctl start mariadb
```

- mariadbの初期設定

```
mysql
drop database test;
update mysql.user set password=password('orenopassword') where user = 'root';
```

※パスワード変更は以下。

```
mysqladmin password orenopassword -u root -p
Enter password:
```

※rootのパスワードを設定。他すべてY。

- データベースの作成

```
mysql -u root -p
create database test_db;
Query OK, 1 row affected (0.00 sec)
```

- テーブルの作成

```
use test_db
Database changed
create table t1(id int, name varchar(32));
Query OK, 0 rows affected (0.01 sec)
```

- データの挿入

```
insert into t1(id, name) values(1, 'mike');
Query OK, 1 row affected (0.00 sec)
insert into t1(id, name) values(2, 'john');
Query OK, 1 row affected (0.00 sec)
select * from t1;
+------+----------+
| id   | name     |
+------+----------+
|    1 | mike     |
|    2 | john     |
+------+----------+
 2 rows in set (0.00 sec)
```

###データ領域設計
MariaDB標準の以下のディレクトリをデータ領域とする。
`/var/lib/mysql`


###バックアップ設計
MariaDBは冗長化され、Active/Activeで動作している。
本来バックアップは1台のノードに取得するだけで充分であるが、ダンプファイルを別筐体や遠隔地に保管していないため、両ノードでバックアップを取得する方針とした。

####取得先
以下のパスにダンプファイルを出力する。
`/backup`

####バックアップ取得
日次でダンプを取得する。
`/etc/crontab` に以下を追記。

```
 0 22 * * * root /script/bin/mariadb_backup.sh
```

実行されるスクリプトの内容は以下。
※手抜きすぎて、すみません…。

```shell:/script/bin/mariadb_backup.sh
 #!/bin/sh
 
 for db in <aaa db> <bbb db>
 do
   /bin/mysqldump --user=root --databases $db --password=<パスワードを入力> > /backup/${db}_dump.sql
 done
```

####バックアップファイルのローテーション
logrotatedで管理する。
設定ファイルは以下。

```/etc/logrotate.d/mariadb_dump
/backup/*_dump.sql {
  daily
  rotate 5
  missingok
}
```

####リストア
リストアは以下の感じで行うらしい。
 mysql -u root < /backup/dump.sql
冗長構成を取っているため、多重障害を考慮しなければ、最新状態のDBは稼動状態で残っているはずなのでロールフォワードについては考えていない。

###接続設定
各自の端末から接続できるユーザを作成する。最強権限なので取り扱い注意。

```
create user boku@"192.168.%" identified by 'bokunopassword';
grant all privileges on *.* to boku@"192.168.%";
```

### 何か用設定
例えばwiki用のDBを作成する手順だと以下のようになります。

- mariadbに接続する。

```
 mysql -u root -p
```

- userを作成する。

```
create user wiki@localhost identified by 'wikinopassword';
create user wiki@<wikiサーバーのIPアドレス> identified by 'wikinopassword';
```

- databaseを作成する。

```
create database wiki;
```

- userに権限を与える。

```
grant all privileges on wiki.* to wiki@<wikiサーバーのIPアドレス>;
flush privileges;
```

- mariadbからログアウトする。

```
quit;
```

#障害復旧
- すべてのノードでmariadbを停止する。

```
systemctl stop mariadb
```

- 1台ずつ起動し、最終コミットを確認する。

```
galera_new_cluster
mysql
show status where variable_name like 'wsrep_last_committed';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| wsrep_last_committed | 14    |
+----------------------+-------+
1 row in set (0.00 sec)
```

※確認できない場合は、最終更新ノードではないと思われる。MariaDBで勝手に判断して起動を抑止してくれている模様。

- 最終コミットの値が最も大きいノードが最新のデータベースを保持していると判断する。
- 最新のデータベースを保持しているノードの設定を書き換える。

```
vi /etc/my.cnf.d/server.cnf
wsrep_cluster_address=gcomm://
```

- 最新のデータベースを保持していないノードの設定を書き換える。

```
vi /etc/my.cnf.d/server.cnf
wsrep_cluster_address=gcomm://<レプリケーション対向ノードのIPアドレスを指定>
```

- 最新のデータベースを保持しているノードでclusterの起動コマンドを実行する。

```
galera_new_cluster
```

- 最新のデータベースを保持していないノードでmariadbの起動コマンドを実行する。

```
systemctl start mariadb
```

#操作
##起動
###1台目のノード

```
galera_new_cluster
```

###2台目以降のノード

```
systemctl start mariadb
```

##停止
###すべてのノード

```
 systemctl stop mariadb
```