CentOS7 + MariaDB でGTIDレプリケーション構築


検証環境

  • CentOS 7.3
  • MariaDB 10.1.24
  • DBマスタサーバ(IP: 192.168.0.1)
  • DBスレーブサーバ(IP: 192.168.0.2)

MySQLでGTID有効のレプリケーション構築を行う手順とは大きく異なりますのでご注意ください。

レプリケーション構築に関するMySQLとの違い

MariaDB10.0以降であればGTIDの設定をするだけでクラッシュセーフになるようです。
MySQL5.6以降と異なり、MariaDBは GTID(Global Transaction ID)がデフォルトで有効になっています。

したがって、設定ファイルにGTIDモードを有効にするための以下設定を書く必要はありません。
(※ 書いたらエラーで起動しなくなります)

gtid-mode = ON
enforce-gtid-consistency

また、GTIDの状態は mysql.gtid_slave_pos テーブルに書き込まれるため、以下設定も同様に必要ありません。

relay_log_info_repository = TABLE
relay_log_recovery = ON
 

MariaDBとMySQLの設定値の違いは公式に記載があります。

System Variable Differences Between MariaDB 10.1 and MySQL 5.6
System Variable Differences Between MariaDB 10.1 and MySQL 5.7

1. 事前準備

初めてレプリケーション構築を行う場合、このステップは飛ばして結構です。

もし既存のレプリケーションやログが残っているDBで新たに構築し直す場合、ログをクリアしておく必要があります。

この作業を怠るとダウンしたマスタをスレーブ群に加える際、誤動作の原因となるようなので注意してください。

スレーブ側のMariaDBで実行
STOP SLAVE;
RESET SLAVE ALL;
マスタ側のMariaDBで実行
DELETE FROM `mysql`.`gtid_slave_pos`;
RESET MASTER;

datadir(デフォルト /var/lib/mysql) に既存のバイナリログが出力されている場合は退避しておきます。

/var/lib/mysql
# バイナリログのファイル名を "slave-bin" と指定している場合

$ mkdir mysqlbak-yyyymmdd
$ mv /var/lib/mysql/slave-bin.* ./mysqlbak-yyyymmdd

2. マスタ側にレプリケーション用ユーザを作成

レプリケーションのみ権限を付与したユーザを用意しておきます。

マスタ側のMariaDBで実行
CREATE USER 'repl'@'192.168.0.2' IDENTIFIED BY '[パスワード]';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.0.2';
FLUSH PRIVILEGES;

3. マスタ側の設定ファイルを編集

systemctl stop mariadb
vi /etc/my.cnf.d/server.cnf
[mysqld]
server-id = 1        # スレーブと異なるサーバIDにする
log-bin=master-bin   # 任意のバイナリログファイル名
binlog-format = ROW
log-slave-updates
systemctl start mariadb

datadir(デフォルト /var/lib/mysql) にlog-binで設定したファイル名のバイナリログが出力されているか確認します。
また、設定が正常に反映されているかどうかは、以下の方法で確認できます。

SHOW VARIABLES LIKE 'server_id';

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 1     |
+---------------+-------+

4. スレーブの設定ファイルを編集

systemctl stop mariadb
vi /etc/my.cnf.d/server.cnf
[mysqld]
server-id = 2      # マスタと異なるサーバIDにする
read_only          # 意図しない改変を防ぐために推奨
log-bin=slave-bin  # 任意のバイナリログファイル名
log-slave-updates
systemctl start mariadb

datadir(デフォルト /var/lib/mysql) にlog-binで設定したファイル名のバイナリログが出力されているか確認します。

5. マスタのダンプファイルを取得

マスタ側で実行
mysqldump --all-databases -u root -p --master-data=2 --single-transaction --routines > dump.sql

ダンプファイルから CHANGE MASTER TO と書かれた行を検索し、バイナリログファイル名とポジションをメモしておきます。
私の環境の場合、grep使うとかなり長い文字列でヒットしてしまったため、viで開いて/検索しました。

こんな行があるはず
CHANGE MASTER TO MASTER_LOG_FILE='xxxxx-bin.000001', MASTER_LOG_POS=xxx;
【2017.12.08 追記】

SHOW MASTER STATUS クエリを実行することで、ダンプファイルを直接開いて検索する方法と同様にバイナリログファイル名とポジションを取得可能なようです(記事コメント欄参照)。

6. マスタの現時点でのGTIDを調べる

さきほどメモしたバイナリログファイル名とポジションをもとに、現時点でのGTIDを調べます。

マスタ側のMariaDBで実行
SELECT BINLOG_GTID_POS( "xxxxx-bin.000001", xxx );

MariaDBのGTIDは「ドメインID + サーバID + サーバーごとのトランザクション番号」というフォーマットで構成されています。
'0-1-1' のような形式のGTIDがヒットするはずなので、またメモしておきます。

※ ここで空が返ってきてしまう場合、何かしら適当なUPDATE文を投げてMariaDBの再起動を行い、ダンプ取得の手順からやり直せばヒットするようになります。

7. スレーブにリストア

マスタのダンプファイルをもとにスレーブ側でリストアします。

スレーブ側で実行
mysql -f -u root -p < dump.sql

8. スレーブにGTIDを設定する

手順6でメモしておいたGTIDを設定します。

スレーブ側のMariaDBで実行
SET GLOBAL gtid_slave_pos = '0-1-1';

9. CHANGE MASTERの実行とスレーブ開始

スレーブ側で以下を実行します。

スレーブ側のMariaDBで実行
CHANGE MASTER TO
  MASTER_HOST     = '192.168.0.1',
  MASTER_USER     = 'repl',
  MASTER_PASSWORD = '[replユーザのパスワード]',
  MASTER_USE_GTID = slave_pos;

START SLAVE;
SHOW SLAVE STATUS \G

CHANGE MASTER TO の設定内容は /var/lib/mysql/master.info に反映されます。
START SLAVE でスレーブを開始後、SHOW SLAVE STATUS でステータスを表示します。
以下のステータスが返ってくれば問題ありません。

Slave_IO_State Waiting for master to send event
Slave_IO_Running Yes
Slave_SQL_Running Yes
Last_Errno 0
Last_Error
Last_IO_Errno 0
Last_IO_Error
Last_SQL_Errno 0
Last_SQL_Error
Gtid_IO_Pos [設定したGTID]

GTIDの状態は以下の方法でも確認可能です。

SELECT * FROM `mysql`.`gtid_slave_pos`

+-----------+--------+-----------+--------+
| domain_id | sub_id | server_id | seq_no |
+-----------+--------+-----------+--------+
|         0 |      1 |         1 |      1 |
+-----------+--------+-----------+--------+

10. 動作確認して設定完了

マスタ側で適当なUPDATE文を流してみて、更新がスレーブ側にも反映されていれば作業完了です。

【Case1】 マスタが落ちた場合

以降の手順は未検証です。メモ書き程度にご参考ください。

マスタ(192.168.0.1 以降、旧マスタ)が落ちてしまい、
スレーブ(192.168.0.2)を新マスタに昇格させる必要がある場合、
スレーブ群(192.168.0.3〜)にマスタの変更を通知する必要があります。

スレーブ群のMariaDBで実行
CHANGE MASTER TO
  MASTER_HOST = '新マスタIP(192.168.0.2)',
  MASTER_PORT=3307;  -- ポート番号の指定が必要な場合

これでスレーブ → マスタ昇格の作業自体は完了ですが、
旧マスタからスレーブに転送し損ねたGTIDが無いか、後々チェックしておく必要があります。

旧マスタのMariaDBで実行
-- 件数が莫大になる可能性もあるのでLIMITは必ず付与する
SHOW BINLOG EVENTS IN 'xxxxx-bin.000001' LIMIT 20 \G

*************************** 1. row ***************************
   Log_name: xxxxx-bin.000001
        Pos: xxx
 Event_type: Gtid
  Server_id: 1
End_log_pos: xxx
       Info: BEGIN GTID 1-1-4

最後に出力された Info: BEGIN GTID に記載のGTIDが最新ということになると思います。
mysqlbinlog を使って確認することもできます。

もし、未転送のGTIDがある場合、新マスタをいったん旧マスタのスレーブ構成にして、そのGTIDでスレーブを開始すると補填できるようです。

正直、ここの流れが具体的によく分かっていません。
→ 新マスタを停止 & 旧マスタ起動
SET GLOBAL gtid_slave_pos = '未転送のGTID';
CHANGE MASTER TO & START SLAVE で一時的に旧マスタのスレーブ化
→ 同期できたら STOP SLAVE & CHANGE MASTER TO の設定をクリアする

という流れでしょうか…。
未転送のGTIDで操作したレコードと同レコードに対して、すでに新マスタ側で何かしらの操作が行われている場合はどうなるの?という疑問があります。
(見当違いなことを言っているかもしれない)

【Case2】 落ちた旧マスタをスレーブ化する

落ちてしまった 旧マスタ(192.168.0.1)が復旧したら、スレーブ化します。
レプリケーション用のユーザは事前作成しておく必要があるので注意してください。

旧マスタのMariaDBで実行
CHANGE MASTER TO
  MASTER_HOST = '新マスタIP(192.168.0.2)',
  MASTER_USER = 'repl',
  MASTER_PASSWORD = '[replユーザのパスワード]',
  MASTER_USE_GTID = current_pos;

MASTER_USE_GTIDslave_pos ではなく current_pos を設定している点に注意が必要です。

gtid_slave_pos スレーブSQLスレッド(*1)が最後に実行したトランザクションのGTID
gtid_current_pos 最後に処理したトランザクションのGTID(*2)

(*1)マスタから転送されたトランザクションのうち、最後に実行されたGTID
(*2)スレーブが直接実行したSQL(エラー修復など)も含む、最後に実行されたGTID
    -> *2 は自身のサーバのみで実行されたGTID(他のサーバに存在しないGTID)を含んでいる

旧マスタはもともとスレーブではないため、slave_pos 自体をまだ持っていません。
そのため、まずは current_pos で自身の最新GTIDをセットしているわけです。
START SLAVE でいったん同期すれば、MASTER_USE_GTID = slave_pos に変更してOKだと思います。

ただし、最新のGTIDが分かっているなら以下の手順でも構わないようです(手順8〜9と同じ)。

最新のGTIDを指定して旧マスタをスレーブ化
SET GLOBAL gtid_slave_pos = 'x-x-xxx';

CHANGE MASTER TO
  -- (...中略...)
  MASTER_USE_GTID = slave_pos;

参考記事