MariaDBでのレプリケーションに関して。
「レプリケーション」とは「レプリカ(複製)を作成する」と言うことなんですね。なるほど。
ざっくりまとめれば、DBとしてマスター(更新も含めて通常利用する方)とスレーブ(マスターのバックアップ)の2つが存在し、マスター側に発生した変更がスレーブ側にも自動的に反映される仕組みで、基本的にはリアルタイムに近いバックアップおよび迅速な障害復旧を目的としたものと言えるかと思います。
更新はマスターに対してしか行えませんが、参照はスレーブに対して行っても良いため、負荷分散のためにマスターは更新用、スレーブは参照用と言うように使い分ける方法もあるようです。ただ、MariaDBにおけるレプリケーションではマスターにおける更新がスレーブで参照可能になるまでに若干のタイムラグがあるようなので、その辺も考慮すると余程負荷分散に関するニーズが高くなければスレーブの用途はあくまでバックアップ(待機)に止めておきたいと思います(現在のスキル的には)。
ということで、以下にレプリケーション環境構築の手順を示します。
なお、レプリケーションの目的には当然ながら耐障害性が含まれると思いますのでマスターとスレーブは別ハード上にあるべきだと思いますが、下記内容は1台のPC(Mac)上にVirtualbox/Vagrantで仮想サーバを2台用意して試作したものです(実際に別ハードを用いた場合と手順的に違いは発生しないと思いますが)。
前提条件は以下の通り。
MariaDB : 5.5.68
マスターのIPアドレス: 192.168.33.20
スレーブのIPアドレス: 192.168.33.21
※192.168.33.xxのLAN上に上記2台のサーバが載っているイメージ。
【マスター】my.cnf設定
マスターに関する「/etc/my.cnf」の設定内容は以下の通り。
[mysqld]
server-id=1
log-bin=mysql-bin
binlog-format=ROW
expire_logs_days=7
「server-id」はレプリケーション環境内において各DBを識別する情報で、マスター・スレーブで異なる数字が設定されていれば問題ありません。
「log-bin」はバイナリログを有効にする設定です。バイナリログはDBに対する更新操作(INSERT,UPDATE,DELETEやトランザクションの開始・終了等)を記録したもので、レプリケーションにおけるマスターとスレーブの同期はこのバイナリログに記録された内容に準じて行われるようです。なお、設定している値はバイナリログ記録用のファイル名決定に用いられるもので、適当な(任意の)文字列でOKです。
「binlog-format」はバイナリログのフォーマットに関する設定で「statement」と「row」の2種類があるようです。デフォルトは「statement」ですが、こちらだと不確実性があるようなので、安全のために「row」になるよう設定しておきます。
「expire_logs_days」はバイナリログ保存期間(日数)に関する設定で、これを指定しないと制限なくログを残し続けるようです。その場合、当然ながらディスク容量を圧迫して行くことになるかと思います。バイナリログに関してはレプリケーション以外に障害時のDB復旧にも用いられますが(と言うかこちらが本来の目的かと)、障害の復旧に関しては通常は定期的にバックアップを残している前提の元に、直近のバックアップの内容反映(リストア)+バイナリログに残された直近バックアップ以降の更新操作結果の反映(リカバリ)という形で行われますので、この観点から判断すればバイナリログはバックアップ間隔より多少長めにとっておけば十分ということになります。バックアップは毎日定時に採取しているケースが多いと思いますので、その場合はバイナリログの保存期間も1日以上であれば良いのですが、一応バックアップ採取に失敗しているケースなども考慮してちょっと長めに(ここでは7日分)残しておく形にします。
上記設定を行った後、これらを有効にするためにMariaDBを再起動します。
systemctl restart mariadb.service
上記結果、「/var/lib/mysql」配下にバイナリログが採取されるようになったかと思います。
【マスター】レプリケーション用ユーザー作成
レプリケーションを行う場合、その目的に特化したユーザーで行うようにするのが通常のようです(安全性を考えるとそうでしょうね)。
具体的には以下のようなSQLを実行します(mysqlコマンドやphpMyAdminのSQLフォームなどを利用する想定)。
CREATE USER '<ユーザー名>'@'192.168.33.%' IDENTIFIED BY '<パスワード>';
GRANT REPLICATION SLAVE ON *.* TO '<ユーザー名>'@'192.168.33.%';
「CREATE USER」でユーザーを作成し、「GRANT REPLICATION SLAVE」でレプリケーション操作に特化した権限を与えています。
一応同LAN内からであれば同ユーザーでマスターの操作が可能になるような設定になっていますが、必要性に応じてアクセス元ホストの指定は変更してください。
【マスター】DBのバックアップ
マスターとスレーブの初期状態を合わせるために、マスターでバックアップを採取し、それをスレーブにリストアします。
まずはマスターで以下の方法でバックアップを採取します。
mysqldump -u root -p --all-databases --flush-logs --single-transaction --master-data=2 > master.db
「–all-databases」はマスター上のMariaDBにある全DBを採取することを意味します。
「–flush-logs」はバックアップ採取後に新しいバイナリログファイルを作成することを意味します。レプリケーションでは本操作で採取したバックアップからスレーブの初期状態を構築するため、同期させるべき更新操作も当然ながら本処理以降に行われたものということになります。よって、ここでファイルを分けておくことで以降の同期処理がやり易くなるということかと思います。
「–single-transaction」はロック(排他制御)の代わりにトランザクションを用いて矛盾のないバックアップを採取する方式を意味します。ロックを行わないことでDBの運用に対する影響が少ないというメリットがあるようですが、トランザクションを用いるという前提なのでInnoDBでは有効でもMyISAMでは無効(矛盾が発生する余地あり)です。ただ、昨今では自製DBでMyISAMを用いることはほとんどないですし、MariaDB内全DBが対象であることを考えるとDB「mysql」内の多数のテーブルがMyISAMである点が問題になりますが、バックアップ中にDB「mysql」に更新が発生するような操作(ユーザー追加や権限追加、ストアドプロシージャ作成など)を行うこと(必要)などないので、トランザクションが無効なケースは考慮しなくて良いとの判断です。そもそもレプリケーション環境構築は運用開始以前、もっと言えばシステムとしての初期環境構築時に実施するので、その段階でバックアップ時に更新が発生する可能性を考慮する必要自体があるかどうかも疑問ではありますが、一応ネット上での諸先輩のご意見を参考にして、この辺のオプションはつけておこうと思ったというのが正直なところです。
「–master-data」はバックアップ時点のポジション情報を出力することを意味します。ここで言う「ポジション情報」とはバックアップ採取段階でバイナリログがどこまで進んでいたかを示す情報であり、具体的にはバイナリログファイル名と同ファイル内の位置(ポジション)で表されるものです。値として2を設定しているのは、ポジション情報をバックアップファイル内にコメントとして残すことを意味します。ポジション情報に関してはスレーブでの手動設定操作時に用いるもので、リストア自体には必要ないと言うことでコメントとして出力するようにしているようです。
上記操作によりバックアップファイル「master.db」が生成されます。これを以降の手順においてスレーブの初期状態生成に用います。
【スレーブ】my.cnf設定
マスター同様にスレーブに関しても「/etc/my.cnf」に必要な設定を追加します。
[mysqld]
server-id=2
log-bin=mysql-bin
read_only
マスターで触れたように「server-id」は識別子として用いるためマスターとは異なる番号を指定します。
「read_only」はDBを読み込み専用とすることを意味するようです。もしスレーブ側で独自に更新操作を行うとレプリケーションが無効になってしまいます。と言うことで本設定は必要…なのですが、本設定を行っていてもrootユーザーでは更新できてしまいます(実際に事故りました)。要は気軽にrootユーザーを使用してはいけないということでしょうね。
上記設定後はMariaDBの再起動をお忘れなく。
【スレーブ】マスターバックアップのリストア
先にマスターで採取したバックアップをリストアします。
mysql -u root -p < master.db
【スレーブ】スレーブ設定
スレーブとして動作するための各種情報の設定をSQLで行います(例によってmysqlコマンドやphpMyAdminのSQLフォーム等から)。
CHANGE MASTER TO
MASTER_HOST='192.168.33.20',
MASTER_PORT=3306,
MASTER_USER='<ユーザー名>',
MASTER_PASSWORD='<パスワード>',
MASTER_LOG_FILE='<バイナリログファイル名>',
MASTER_LOG_POS=<ポジション>;
「MASTER_HOST」にはマスターのIP、「MASTER_USER」「MASTER_PASSWORD」にはマスターでレプリケーション用に作成したユーザーの名前とパスワードをそれぞれ指定します。
「MASTER_LOG_FILE」と「MASTER_LOG_POS」ですが、バックアップファイル「master.db」の中を見ると以下のような行が発見できるかと思います。
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000008', MASTER_LOG_POS=245;
上記はバックアップ採取時に「–master-data=2」を指定したことで残されたコメントで、ここで示された「MASTER_LOG_FILE」と「MASTER_LOG_POS」をそのまま指定します。
【スレーブ】スレーブ(レプリケーション)の開始
最後に以下のSQLを実行することでレプリケーションが開始されます。
START SLAVE;
状態確認
一応上記までの設定が正しいかどうかを確認してみます。
まずはマスターで以下のSQLを実行します。
SHOW MASTER STATUS;
上記でポジション情報が表示されます。
一方スレーブでは以下のSQLを実行します。
SHOW SLAVE STATUS;
上記結果で確認すべき点は以下の2点です。
- 「Slave_IO_Running」と「Slave_SQL_Running」がYesになっている
- 「Master_Log_File」および「Read_Master_Log_Pos」がマスターで確認したポジション情報の「File」および「Position」と一致している
上記が問題なければ、マスターでDB、テーブル、レコードの追加、変更、削除を行ってみましょう。
比較的リアルタイムにスレーブ側にマスターでの更新結果が反映されることを確認できるはずです。
上記でマスターと同じ内容をスレーブに残すという、レプリケーションの初期目的は達成できました。
本番運用に向けてはマスターの障害発生時にスレーブ側をマスターに切り替えての復旧操作なども確認して行きたいと思いますが、今回はここまで。