とりあえずお手軽にUbuntu一台でMariaDBのマスタースレーブ構築してみるよ

# はじめに

ローカルマシンでMaster-Slave構成のDBへのアクセステストを行うために、とりあえずで構築してみました。
MySQLは良く見かけるので、あえてMariaDBで。galera使って、MultiMaster構成も捨てがたかったけど、実案件でまだ使うことはなさそうなので、古き良きMaster-Slave構成を選択しました。
なお、同一サーバ上で複数のインスタンスを起動するために、mysqld_multiコマンドを使用しています。

使ったものは以下の通りです。

|名前|バージョン|
|:--|:--|
|Ubuntu|16.04.2|
|MariaDB|10.2.12

# 手順

なお、以後、シェル中のsudoは省略しています。

## まずはリポジトリ

[MariaDB公式サイト](https://downloads.mariadb.org/mariadb/repositories/)に従い、リポジトリを追加します。

```
# apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
# vi /etc/apt/sources.list.d/mariadb.list (以下記述)
deb [arch=amd64,i386] http://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb/repo/10.2/ubuntu xenial main
deb-src http://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb/repo/10.2/ubuntu xenial main

# apt-get update
```

## そして、インストール

リポジトリからmariadb-serverをインストールします。

```
# apt-get install mariadb-server
```

余分なユーザーやテーブルを削除した後、一旦、サーバを止めます。

```
# mysql_secure_installation
# service mysql stop
```

## スレーブ用インスタンスの作成

スレーブ用のデータディレクトリを作成し、データの初期設定を行います。

```
# mkdir /var/lib/mysql-slave
# chown mysql:mysql /var/lib/mysql-slave
# mysql_install_db --datadir=/var/lib/mysql-slave
```

## 二つのインスタンスを立ち上げる

my.cnfを複数インスタンス用に変更します。

```
# cp /etc/mysql/my.cnf /etc/mysql/my.cnf.orig
# vi /etc/mysql/my.cnf  (下記の内容を追加)
```

```my.cnf
(追加部分)
[mysqld_multi]
user		= root
password        = hogehoge
mysqld          = /usr/bin/mysqld_safe
mysqladmin      = /usr/bin/mysqladmin

[mysqld1]
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
port		= 3306
datadir		= /var/lib/mysql
general_log_file        = /var/log/mysql/mysql.log
general_log             = 1
server-id		= 1
report_host		= master1
log_bin			= /var/log/mysql/mariadb-bin
log_bin_index		= /var/log/mysql/mariadb-bin.index
expire_logs_days	= 3
max_binlog_size         = 100M

[mysqld2]
pid-file	= /var/run/mysqld/mysqld-slave.pid
socket		= /var/run/mysqld/mysqld-slave.sock
port		= 3307
datadir		= /var/lib/mysql-slave
general_log_file        = /var/log/mysql/mysql-slave.log
general_log             = 1
server-id		= 2
report_host		= slave1
# slaves
relay_log		= /var/log/mysql/relay-bin
relay_log_index	= /var/log/mysql/relay-bin.index
relay_log_info_file	= /var/log/mysql/relay-bin.info
read_only
```

mysqld1は、最初にインストールされたインスタンスでマスター部分になります。binary logを有効にし、server-idを指定しています。
mysqld2が、手動で追加したインスタンスでスレーブ部分になります。mysqld1の内容をコピーしてきて、PID、ソケット、データディレクトリなどをスレーブ用に変更しました。また、ポートを3307にしています。さらに、今回はrelay logを有効にし、read_onlyにしています。

では、mysqld_multiを使って、二つのインスタンスが立ち上がるか確認してみます(なお、この時点では二つのインスタンスはmaster-slaveの関係になっていません)。

```
# mysqld_multi start
# mysqld_multi report   (確認用)

Reporting MariaDB servers
MariaDB server from group: mysqld1 is running
MariaDB server from group: mysqld2 is running
```

## マスターとスレーブ

それでは、マスターからスレーブにデータをコピーし、同期を行うことにします。

### マスター側

まず、マスター側サーバで、レプリケーション用のユーザを作成し、また、binary logの状態を記録しておきます。

```
# mysql -u root -P 3306 -h 127.0.0.1
> grant replication slave on *.* to repl@127.0.0.1 identified by 'REPLのパスワード';
> flush tables with read lock;
> show master status;  (FileとPositionを記録しておく)
+--------------------+----------+--------------+------------------+
| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mariadb-bin.000012 |      663 |              |                  |
+--------------------+----------+--------------+------------------+
```

つづいて、マスター側のデータをダンプします。

```
# mysqldump -u root -p --all-databases --lock-all-tables -P 3306 -h 127.0.0.1 > /tmp/dbdump.db
```

さきほどread lockをかけていたので、忘れずにlockを解除しておきます。

```
# mysql -u root -P 3306 -h 127.0.0.1
> unlock tables;
```

### スレーブ側

続いて、スレーブ側にマスターの設定を行い、スレーブを開始します。
問題なければ、show slave statusでパラメータが表示されるはずです。

```
# mysql -u root -P 3307 -h 127.0.0.1 < /tmp/dbdump.db
> change master to master_host='127.0.0.1', master_port=3306, master_user='repl', master_password='REPLのパスワード', master_log_file='記録したbinary logのファイル名', master_log_pos=記録したbinary logのPosition;
> start slave
> show slave status\G (確認用)
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mariadb-bin.000012
          Read_Master_Log_Pos: 663
               Relay_Log_File: relay-bin.000018
                Relay_Log_Pos: 964
                            (略)
```

## ユーザと作業用databaseの作成

スレーブ側インスタンスにはread_onlyを付けていますが、このままでは、最初に作られた万能ユーザしか居ませんので、書き込みし放題です。
作業用データベースと、作業用ユーザを作成します。
データベース名や、作業用ユーザのIDやパスワードは適宜書き換えてください。(まさかデータベース用アカウントにSCOTT/TIGERを使っている人はいませんよね・・・)。

```
# mysql -u root -P 3306 -h 127.0.0.1
> create database workdb;
> create user scott@'127.0.0.1' identified by 'tiger';
> grant all on workdb.* to scott@'127.0.0.1';
```

## スタートアップ

さて、このままでは、init.dには従来のmysqlが登録されたままになっているため、サーバを再起動したときに、マスター側のインスタンスしか立ち上がらないということになります。
mysqld_multi用のスクリプトを作成し、それと置き換えることにします。

```
# update-rc.d mysql remove
# cp /etc/init.d/mysql /etc/init.d/mysql_multi
# vi /etc/init.d/mysql_multi (以下のスクリプトを作成)
```

mysqld_multiの内容 (ひどい手抜き)

```
#!/bin/bash
#
### BEGIN INIT INFO
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Should-Start:      $network $named $time
# Should-Stop:       $network $named $time
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
### END INIT INFO
#
set -e
set -u
${DEBIAN_SCRIPT_DEBUG:+ set -v -x}

test -x /usr/sbin/mysqld || exit 0

. /lib/lsb/init-functions

SELF=$(cd $(dirname $0); pwd -P)/$(basename $0)

if [ -f /etc/default/mysql ]; then
  . /etc/default/mysql
fi

# Safeguard (relative paths, core dumps..)
cd /
umask 077

case "${1:-''}" in
  'start')
  /usr/bin/mysqld_multi start
  ;;

  'stop')
  /usr/bin/mysqld_multi stop
  ;;

  'restart')
  $SELF stop
  $SELF start
  ;;

  *)
  echo "Usage: $SELF start|stop|restart"
  exit 1
  ;;
esac

```

スクリプトを登録します。

```
# update-rc.d mysql_multi defaults
# update-rc.d mysql_multi enable
```

これで、サーバの起動と終了がserviceコマンドで行えるようになるはず・・・

```
# service mysql_multi start
# mysqld_multi report
Reporting MariaDB servers
MariaDB server from group: mysqld1 is running
MariaDB server from group: mysqld2 is running
```

次に停止の確認。

```
# service mysql_multi stop
# mysqld_multi report
Wide character in print at /usr/bin/mysqld_multi line 599.
Reporting MariaDB servers
MariaDB server from group: mysqld1 is not running
MariaDB server from group: mysqld2 is running
```

あ、あれ・・・。
To-Do: 原因が分かったら記事を修正する。
(未完)

## logrotate(追記)

このままでは、logrotateがマスター側のログのみを対象にしてしまうので、スレーブ側のログも対象にする。

```
# vi /etc/logrotate.d/mysql-server

下の行に、mysql-slave.logを追加します。
/var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log /var/log/mysql/mariadb-slow.log /var/log/mysql/error.log
↓
/var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log /var/log/mysql/mariadb-slow.log /var/log/mysql/error.log /var/log/mysql/mysql-slave.log

あと、ログがうまく書き込まれないケースがあるようなので、maskを640から660に変更しておきます。(調べてない)
create 640 mysql adm
↓
create 660 mysql adm
```

## character-set(追記)

デフォルトだとcharacter-setがlatin1なので、utf8mb4に変更します。
my.cnfにcharacter-setを追記します。

```my.cnf
(追加部分のみ)
[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld1]
character-set-server = utf8mb4

[mysqld2]
character-set-server = utf8mb4
```