MySQL5.5で準同期レプリケーション構築

MySQL5.5を用いた通常・準同期レプリケーション構築の解説です。レプリケーションとは何か、通常・準同期レプリケーションの対比、構築方法、必要な保守作業など。対象読者は多少MySQLサーバの設定を行ったことのある方を想定しています。

基礎知識

レプリケーションを構成する要素・どんな動作をするか・レプリケーションの種類。レプリケーション構築の前に知っておくべきことを解説します。

レプリケーションとは何か

MySQLのレプリケーションはマスターサーバのデータを一つ以上のスレーブサーバに複製することでデータを冗長化する機能です。

レプリケーションを用いれば複数個所にデータベースの複製を設置できるので、荷分散と共に可用性・信頼性を向上させられます。設定は容易で、どのサーバからもSELECT文でデータを参照できます。しかし、更新クエリはマスターサーバにしか行えません。つまり、レプリケーションで書き込みのスケールアウトは出来ません。更新クエリの負荷を分散させる必要が無い場合にはレプリケーションをお勧めします。更新クエリの負荷分散が必要な場合は、クラスタリング設定を行うか、別のソフトウェアを試してください。

通常レプリケーション・準同期レプリケーションの違い

通常レプリケーションの動作

通常レプリケーション特筆すべき点は、マスターサーバはログを出力するだけで自己完結していることです。スレーブサーバの片思い的な動作方式です。

役割に応じた動作|通常レプリケーション

マスターサーバの役割は単純で、更新クエリ実行時にバイナリログを出力するだけです。

スレーブサーバは下記の通り多少がんばります。

  1. レプリケーション権限を持つユーザでマスターサーバにログイン
  2. 今までコミットしたバイナリログからさらに更新があるか確認
  3. 更新があればその部分のバイナリログを取得し実行
  4. マスターサーバからログアウト

スレーブサーバはバイナリログ実行後すぐにログアウトするわけではなく、実際は2~3の動作を繰り返します。

コミット時の動作|通常レプリケーション

実際に更新クエリをコミットした時の振る舞いを見ましょう。

  1. マスターで更新クエリ実行時にバイナリログに記録
  2. スレーブがバイナリログが更新されたことに気付いたら、マスターからスレーブへバイナリログを転送
  3. スレーブで更新クエリを実行

手順「2.」の転送が完了する前にマスターがクラッシュした場合、齟齬が生じ「コミットしたのにデータが巻き戻されてる」という事態に陥る可能性があります。

準同期レプリケーションの動作

準同期レプリケーションのシステム構成要素は通常のレプリケーションと共通。PostgreSQLで言う同期レプリケーションと同じ仕組みです。準同期レプリケーションではマスターはスレーブの面倒を見ます。毎朝登校時間に起こしに来てくれる幼馴染型の動作をします。

役割に応じた動作|準同期レプリケーション

マスターサーバの役割は通常レプリケーションよりも増えます。

  1. クライアントから更新クエリを受け取って、バイナリログをスレーブに転送する
  2. バイナリログを受け取ったスレーブは「受け取りました」サインをマスターに返信してからコミット

スレーブサーバは気楽です。

  1. レプリケーション権限を持つユーザでマスターサーバにログイン
  2. マスターからバイナリログを送られたら「受け取りました」サインをマスターに返信してからコミット
  3. マスターサーバからログアウト

スレーブサーバはバイナリログ実行後すぐにログアウトするわけではなく、実際は2の動作を繰り返します。

一定時間(設定で変更可能)待機してスレーブからの応答が無い場合、マスターはスレーブを無視してバイナリログをコミットします。

コミット時の動作|準同期レプリケーション

実際に準同期レプリケーションを構築したMySQLサーバで更新クエリをコミットした時の振る舞いを見ましょう。

  1. MASTER側からSLAVE側にSQLバイナリログを転送
  2. SLAVE側からMASTER側に「更新出来ますよ」サインを返信
  3. MASTER側・SLAVE側それぞれで更新クエリを実行

この動作手順では、最初にSQLバイナリログを送信しているため、MASTERとSLAVE間で齟齬が生じる可能性は非常に低いです。

冗長化方法の対比

通常レプリケーションの動作準同期レプリケーションの動作で見てきたように、構成する要素は同じで動作の違いは小さいです。が、それぞれ癖がありますので、どちらを選択するかは吟味しておくべきです。

両者の対比を紹介しますが、データの完全性を求めるなら準同期レプリケーション。数分の更新遅延を気にしないなら通常レプリケーションが私の結論です。

応答速度

準同期レプリケーションはクエリ実行時にバイナリログをスレーブに送って応答を待つため、通常のレプリケーションよりコミットまでの応答時間が長くなります。

コミットデータの完全性

通常レプリケーションで、マスターが更新したバイナリログを取得する前にマスターが落ちると、「コミットしたのに巻き戻ってる…」という自体に陥る可能性があります。また、マスターがコミットしてからスレーブがコミットするまでの間にスレーブのデータを参照すると、古いデータを読み込むことになります。つまり、通常レプリケーションは完全性に難があるわけです。金銭を取り扱うようなシステムでは通常のレプリケーションを控えねばなりません。

保守性

保守は通常レプリケーションの方が楽です。マスターはスレーブと完全に独立して動作していますし、スレーブを落としてもマスターの動作が遅くなることはありません(準同期では一定時間スレーブの応答を待機する)。そして、多少設定が楽です。

レプリケーションの構築

複数のレプリケーションを構築する場合も手順は同じなので、『一台のマスター・一台のスレーブ』を構築します。

  • 「同じ方法で再構築出来る」をモットーに構築します。
  • 通常のレプリケーションも準同期レプリケーションも構築方法はほとんど同じです。異なる点では適宜記述します。
  • この構築例のOSはマスター・スレーブ共にSSH, MySQL-Serverインストール済みのCentOSを想定していますが、他の構成でも流用できます。

手順

  1. 構成の設計とMySQLサーバ設定の確認
  2. マスターのレプリケーション設定・データベースのコピー
  3. マスターのバックアップデータをスレーブに転送
  4. スレーブのレプリケーション設定
  5. 動作確認

構成の設計とMySQLサーバ設定の確認

下記の構成でレプリケーション構成を行います。分かる変数を各自の環境に合わせたら次に進みましょう。

構築するレプリケーションの種類

不明 通常レプリケーション 準同期レプリケーション

マスター ネットワーク情報

ホスト(IP/DN):

MySQL ポート:

MySQL サーバID:

MySQLレプリケーション ユーザ:

MySQLレプリケーション パスワード:

MySQL現在のバイナリログファイル名:

MySQL現在のバイナリログ位置:

スレーブ ネットワーク情報

ホスト(IP/DN):

MySQL サーバID:

SSH ポート:

SSH ユーザ:

SSH パスワード:

コンソール操作

SSHなどを用いて実際にサーバ機を操作します。

マスターサーバの操作

マスターの MySQLサーバーが使用するポートを解放

レプリケーションを行うには、マスター側のMySQLサーバの使用するポートが外部に公開されている必要があります。MASTERでファイアーウォールを利用している場合、TCP 3306 番ポートを開放して下さい。また、アウトバウンドのサーバとレプリケーションを行う場合は、ルータのネットワークアドレス変換を設定してください。

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

まず、レプリケーション権限のみを持ったレプリケーション専用のユーザーを作成します。MASTERのMySQLコンソールで以下のSQLを実行します。

GRANT REPLICATION SLAVE ON *.* TO replication_user@'slave.example.com' IDENTIFIED BY 'password';

ユーザ作成に成功したら、設定を反映してください。

FLUSH PRIVILEGES;

マスターのレプリケーション設定とデータベースの複製

レプリケーション構築の勘所で、すべきことは下記2点です。

  1. マスター用の設定を行う
  2. スレーブ側にマスターのデータを転送するため現在状況を複製する

「1.」では設定読み込みのためにMySQLサーバを再起動する必要がありますし、「2.」ではデータコピー中にユーザがデータベースに書き込めなくする必要があります(バックアップ中にデータを更新されては困る)。途中で手を止めるとサーバ停止時間が伸びてしまうので、ひと通り手順をさらってから作業に進んでください。 マスター用の設定を行う

「マスター用の設定」とは、下記三点のことを指します。すでに設定済みの場合はスキップしてOKです。

  1. SQL実行時にクエリのバイナリログを出力する
  2. どのサーバか識別するためサーバIDを付与する
  3. 準同期レプリケーションを行う場合に準同期レプリケーションマスター用のモジュールを読む

これらの変更はvi /etc/my.cnf で [mysqld] 中に下記を追加して行います。

  1. server-id=20 # サーバー固有のIDを指定します
  2. rpl_semi_sync_master_enabled=1 # 準同期レプリケーションのみ追加 準同期レプリケーションマスター動作を有効にします
  3. rpl_semi_sync_master_timeout=1500 # 準同期レプリケーションのみ追加 更新時、SLAVEが応答しない時のタイムアウト時間を1.5秒に設定します
  4. log-bin # バイナリログを生成するようにします
  5. expire_logs_days = 14 # ログの保持を保証する期間(日数)です。0以外の値にすると、ログローテーション・サーバ再起動のタイミングで指定日数以上経過したログファイルは自動的に削除されます。

編集したら /etc/rc.d/mysqld restart でマスターを再起動し、設定を反映してください。 スレーブ側にマスターのデータを転送するため現在状況を複製する

下記役割を持つ、A,・B 2つのターミナルを用意します。

  • A:マスターのMySQLコンソール上でSQLクエリ実行する
  • B:マスターのシェルの操作を行う

ここからノンストップ作業

ターミナルAで下記SQLを実行し、 MySQLサーバの書き込みを禁止します。※ログアウトするとロックが解けてしまうため、コピーが完了までAはMySQLサーバからログアウトしてはいけません

FLUSH TABLES WITH READ LOCK;

下記SQLを実行し、現在のログ位置を取得します。FileとPositionの値をメモしておいてください。→上のフォームにメモってくる

SHOW MASTER STATUS;

mysql> SHOW MASTER STATUS;

FilePositionBinlog_…
mysqld-bin.000001805 

1 row in set (0.00 sec)

スレーブ側にデータを転送する前に圧縮します(データサイズや回線速度によっては圧縮せずに cp を使った方が速く終わる場合もあります。要はマスターのDBデータをスレーブにコピー出来れば良いので、適宜方法を選択してください)。

  • cd /var/lib/mysql
  • tar zcvf master-mysql-data.tar.gz *

ターミナルAで下記クエリを実行してロックを解除してください。

UNLOCK TABLES;

ここまでノンストップ作業

マスター→スレーブ データ転送

前項で作成したマスターデータベースの複製をスレーブに転送します。転送方法はSFTPでもFTPSでもSCPでもUSBメモリでもフロッピーディスクでも構いません。

下の例ではマスター側のコンソールでSFTPを使って転送します。

  • cd /var/lib/mysql
  • sftp -oPort=22 replication_user@slave.example.com
  • replication_user@slave.example.com’s password: # パスワード応答
  • cd /var/lib/mysql
  • put master-mysql-data.tar.gz

スレーブサーバの操作

スレーブ 設定ファイル

スレーブとして動作するように設定ファイルを編集します。

vi /etc/my.cnf で [mysqld] 中に下記を追加してください。

  • server_id=20 # サーバー固有のIDを20に設定します
  • plugin-load=rpl_semi_sync_slave=semisync_slave.so # 準同期レプリケーションのみ追加 準同期レプリケーションスレーブ動作を有効にします

※旧ヴァージョンのMySQLサーバでレプリケーションを行っていた方へ…MySQLのヴァージョン5.5未満のレプリケーションで使用していた master_host, master_port, master_user, master_password の設定項目は、my.confに記述できなくなりました。これら変数を my.cnf に記述してMySQLサーバーを起動しようとすると、 /var/log/mysqld.log には [ERROR] /usr/libexec/mysqld: unknown variable ‘master_host=master.example.com’ とエラーメッセージが出力され、起動ができません。これらの変数はSLAVEで CHANGE MASTER TO ... クエリを実行した時に自動的に /var/lib/mysql/master.info に書き込まれるようになりました。

編集したら /etc/rc.d/mysqld restart でSLAVEを再起動し、設定を反映してください。

マスターを指定

スレーブサーバに「どのMySQLサーバをマスターとするのか」の情報を与える必要があります。スレーブのMySQLコンソールで下記SQLを実行してください。

CHANGE MASTER TO master_host='master.example.com', master_port=3306, master_user='20', master_password='password', master_log_file='mysqld-bin.000001', master_log_pos=805;

実行後 /var/lib/mysql/master.info が生成されるのが確認できます。

マスターと同期開始

スレーブのMySQLコンソールで下記SQLを実行してください。

START SLAVE;

動作テスト

スレーブの状態を確認する

SLAVE側のMySQLコンソールで下記クエリを実行し、レプリケーションが構築できているか確認してください。エラー無くマスターと同じ位置までログが進んでいれば正常です。

SHOW SLAVE STAUS;

PCの再起動

スレーブサーバのPC再起動です。PCを再起動してもスレーブ状態は維持されます。レプリケーションの再設定(START SLAVE)が不要なのが分かりました。

マスターでコミット

マスターでの更新クエリ実行です。マスターにテーブルを作って、SLAVE側で反映されるかを確認してください。

CREATE DATABASE hoge;

SLAVE側でも同じ更新が行われるはずです。

スレーブでコミット

※レプリケーションが壊れる可能性があるので本番環境でこのテストを行わないでください。

スレーブ側で更新クエリを実行するとどうなるか。スレーブ側でも更新クエリは実行できてしまいます。マスターとデータの齟齬が生まれてしまうので、SLAVE側での更新は行わないようにしてください。スレーブ側でデータベースを更新出来なくするのもひとつの手ですが一長一短です。スレーブ側で更新できるなら、マスターが不慮に停止しても迅速にサービス復旧できるからです。

スレーブダウン時のコミット

準同期レプリケーション構築時、スレーブがダウンしている場合の動作です。スレーブのMySQLサーバーをストップしてからマスターで更新クエリを実行すると、 rpl_semi_sync_master_timeout で指定した時間 [ms] 待機してから更新クエリが実行されます。このクエリ実行後にスレーブのMySQLサーバーを立ち上げると同じ更新が行われました。スレーブがダウンしても expire_logs_days で示した日数以内に再起動出来れば問題ないようです。

メンテナンス

レプリケーション構築後にどんなメンテナンスが必要かと言っても場合によりけりなのですが。個人的にチェックすべきと思った点を抑えます。

障害発生時

スレーブサーバが死んだ時はほぼ問題無しです。準同期レプリケーションであれば更新クエリ実行時に rpl_semi_sync_master_timeout で指定した時間待機するので多少パフォーマンスが低下しますが、これまでの手順どおりに再度レプリケーションを組み直せば良いだけです。

問題はマスターサーバが死んだ場合です。フェイルオーバーが必要になります。マスターサーバが息をしていない場合はスレーブサーバで下記クエリを実行してください。

RESET MASTER;

これでスレーブはマスターに昇格し、元マスタのバイナリログを読みに行かなくなります。なお、既存のバイナリログ関係ファイルはすべてリセットされます。

バイナリログのサイズ

データベースの更新頻度が低ければ2週間のバイナリログ自動削除で大丈夫ですが、更新頻度が高くなるとものすごい勢いでバイナリログが書き込まれることになります。「ハードディスクの中がログファイルでパンパンだぜ」という事態に陥る可能性があるわけです。時折ハードディスクの残量とバイナリログの増加速度を見てバイナリログの保持期間を調整してください。

バックアップ

レプリケーションを組むだけで安心してはいけません。RAIDを組んでもバックアップは別途必要と言われるように、レプリケーションを組んでもDBのバックアップは別途取得するようにしてください。

貴方の中の全どぢっ娘がうっかりデータ全削除をしてしまう可能性はゼロではないからです。

その他

後書き

MySQL5.5で準同期レプリケーションをしようとした時に、頭から尻尾まで解説したサイトが見つかりませんでした。大抵、通常のレプリケーションを組んであるのが前提だったり、細部がはしょってあったり。それで、MySQL5.5を用いた準同期レプリケーション設定の解説をしようと思いました。

しかしながら、なかなかうまくいかないもので。作ってから「僕の解説中途半端だお…」と気づきました。気付いたもののなかなか更新出来ず、半端な解説を掲載したまま一年近くが経過してしまいました。

数日ああでもないこうでもないと考えて作成したMySQL5.5+準同期レプリケーション構築の解説ドキュメント。多少なり役立てたのであれば幸いです。

とみんのブログ – 今更ながらMySQLのレプリケーション その1 準同期レプリケーションについての解説しています。

現場指向のレプリケーション詳説 運用しながらのレプリケーションの構築方法を解説しています。

半袖野郎 blog.hansode.org – 2009年05月08日 master.infoの構造・作り方を解説しています。

OpenGroove – レプリケーション時のRESET MASTERとRESET SLAVE レプリケーション時のRESET MASTER・RESET SLAVEコマンドの動作を解説しています。