第34回:MySQLレプリケーション方式(非同期・準同期)の仕組みと設定方法
技術者向け・データベースの技術情報発信
MySQLのレプリケーション方式には、デフォルトの非同期型と、プラグインをインストールすることでサポートされる準同期型が提供されています。
非同期レプリケーションはMySQL 3.23.15からサポートされ、準同期レプリケーションはMySQL 5.5から追加されました。
今回のブログでは、それぞれのレプリケーション方式の仕組みと、特徴の違いによる使い分けや設定方法について解説します。
1.MySQLのレプリケーション機能
MySQLのレプリケーションを有効化することで、複数のサーバで同一のデータを保持することができます。
レプリケーションの主な目的としては、障害時に備えた冗長化、負荷分散による性能向上、サーバを分けることによる役割分担、バックアップの代用などが挙げられます。
MySQLのレプリケーションは、1台をソース(マスタ)、他の複数のサーバをレプリカ(スレーブ)として、マスタからコミットされたトランザクションログの内容をレプリカ(スレーブ)に同期します。
MySQLへの更新処理は全てソース(マスタ)に対して行うことで、レプリカ(スレーブ)へデータ整合性が取れたレプリケーションを実現します。
レプリカ(スレーブ)は読み取り専用として利用することができるため、読み取りアクセスが多いデータ集計などの処理にレプリカ(スレーブ)を利用することで負荷分散が図れます。
一般的に、データベースのレプリケーションには、データ複製のタイミングによって同期型と非同期型に分類することができます。
●同期型
データの変更から全ての複製先への同期が一連の処理で行われる
●非同期型
データの変更と複製先への同期を分け、それぞれ独立して処理される
MySQLのレプリケーションでは、デフォルトでは非同期型をサポートし、プラグインをインストールすることで同期型と非同期型の中間に当たる準同期型をサポートしています。
2.非同期レプリケーションと準同期レプリケーションの仕組み
非同期レプリケーションと準同期レプリケーションの仕組みについて解説します。
先ほど、「ソース(マスタ)からコミットされたトランザクションログの内容をレプリカ(スレーブ)に同期する」と説明しました。
レプリケーションを利用していない構成と同様に、MySQLにデータ更新を行い、コミットを実行すると実データの更新と更新内容をバイナリログに書き込みます。
バイナリログは、リストア時のデータのリカバリに用いられますが、レプリケーションもバイナリログを利用してデータの同期を行います。
MySQLのレプリケーションで同期作業を行っている実体は、レプリカ(スレーブ)サーバの「I/Oスレッド」と「SQLスレッド」です。
●I/Oスレッド
I/Oスレッドは、最初にソース(マスタ)に接続してバイナリログの変更を待ちます。
マスタでトランザクションがコミットされバイナリログの変更が発生すると、I/Oスレッドがマスタのバイナリログをリレーログとしてレプリカ(スレーブ)にコピーします。
リレーログにコピーが終わると、再度ソース(マスタ)に接続してバイナリログの変更を待ちます。
●SQLスレッド
SQLスレッドは、I/Oスレッドによって書き込まれたリレーログを読み取り、レプリカ(スレーブ)サーバのデータ変更を行います。
非同期レプリケーションと準同期レプリケーションは、I/Oスレッドによるリレーログの書き込みをアプリケーションのトランザクションに含めるかどうかが異なります。
それぞれの方式は下記フロー図の流れでレプリケーションを行います。
準同期レプリケーションは後述のとおり、5.6以前と5.7以降でフローが変わったため、5.7以降の流れを記載します(後述のロスレス準同期レプリケーション)。
白丸の項番の処理は、トランザクションの一連処理を表し、黒丸の項番の処理はトランザクション処理とは別の処理を表しています。
どちらのレプリケーションでも、トランザクションをコミットするとデータとバイナリログを同時に変更します。
非同期レプリケーションは、データとバイナリログが更新されると、MySQLサーバがクライアントにコミット完了の応答をします。
その後、トランザクションとは別処理として、I/Oスレッドが更新情報を転送し、リレーログの書き込みを行い、SQLスレッドがデータ変更をします。
一方、準同期レプリケーションは、バイナリログが更新されるとI/Oスレッドにより更新を転送し、リレーログの書き込みを行ってからソース(マスタ)のデータ更新を行い、MySQLサーバがクライアントにコミット完了の応答をします。
コミット完了の応答後に、リレーログを読み取り、レプリカ(スレーブ)サーバのデータ変更を行います。
非同期レプリケーションの処理フロー | 準同期レプリケーションの処理フロー | |
変更トランザクション一連処理 | ①トランザクションをコミット ②コミットデータをデータとバイナリログに書き込み ③クライアントにコミット完了の応答 |
①トランザクションをコミット ②コミットデータをバイナリログに書き込み ③IOスレッドがバイナリログの内容を受け取りスレーブのリレーログにコピー ④ソース(マスタ)のデータを変更 ⑤クライアントにコミット完了の応答 |
変更トランザクション外同期処理 | ➊IOスレッドがバイナリログの内容を受け取りスレーブのリレーログにコピー ➋SQLスレッドがリレーログにコピーされた内容をデータに反映 |
➊SQLスレッドがリレーログにコピーされた内容をデータに反映 |
3.非同期レプリケーションと準同期レプリケーションの特徴比較
2つのレプリケーション方式の大きな違いはコミットの応答タイミングが異なるだけですが、この違いが性能や耐障害性に大きく影響します。
準同期レプリケーションは、クライアントにコミット完了の応答をするためにはリレーログの書き込み完了が必要になるため、非同期レプリケーションよりトランザクションのコミット処理に時間がかかります。
非同期レプリケーションは、応答性能は準同期レプリケーションより高速に処理できますが、ソース(マスタ)の更新内容を転送するのがトランザクション外であるため、ソース(マスタ)障害のタイミングによってはデータをロストする可能性があります。
高速なレスポンスの非同期レプリケーションと、データの信頼性が高い準同期レプリケーションを、利用ケースにより適切に使い分けることが重要です。
非同期レプリケーション | 準同期レプリケーション | |
利用前提 |
|
|
応答性能 |
|
|
耐障害性 |
|
|
用途 |
|
|
4.MySQLレプリケーションの進化(GTID/ロスレス準同期レプリケーション)
2000年5月からサポートされたレプリケーション機能は、バージョンアップの際に機能追加や性能改善が実装されています。
これまでのレプリケーション機能のアップデートの中から、GTIDレプリケーションとロスレス準同期レプリケーションについてご紹介します。
4-1 GTIDレプリケーション
5.6.5よりトランザクションを一意に識別するGTID(Global Transaction Identifiers)が利用可能となりました。
GTIDを有効にしていない環境では、レプリケーションを開始するソース(マスタ)のバイナリログのポジションを明示的に指定する必要がありました。
GTIDを有効にすることで、自動的にレプリカ(スレーブ)側にコピーしていないトランザクションのみを抽出してレプリケーションを開始することができます。
【GTID無しのレプリケーション】
mysql> CHANGE MASTER TO > MASTER_HOST = host, > MASTER_PORT = port, > MASTER_USER = user, > MASTER_PASSWORD = password, > MASTER_LOG_FILE='mysql-bin.00000X', > MASTER_LOG_POS=XXX;
【GTIDレプリケーション】
mysql> CHANGE MASTER TO > MASTER_HOST = host, > MASTER_PORT = port, > MASTER_USER = user, > MASTER_PASSWORD = password, > MASTER_AUTO_POSITION = 1;
4-2 ロスレス準同期レプリケーション
5.5からサポートされた準同期レプリケーションは、ソース(マスタ)のクラッシュによってマスタとレプリカ(スレーブ)間でデータの不整合が起こる可能性がありました。
5.7から rpl_semi_sync_master_wait_point オプションが追加されました。
これはレプリカ(スレーブ)に対して更新を転送するタイミングを設定するものです。
このオプションとAFTER_SYNC(デフォルト)により、障害時にソース(マスタ)とレプリカ(スレーブ)間でデータの不整合が起こることなくレプリケーションすることが可能になりました。
このような rpl_semi_sync_master_wait_point = AFTER_SYNC で構成したレプリケーションは、ロスレス準同期レプリケーションと呼ばれます。
値を AFTER_COMMIT に変更した場合は5.6までと同じ挙動になります。
5.MySQLレプリケーション構築手順
PC上のVirtualBoxに、CentOS8とMySQL8.0.26をインストールし、同一サーバ内にポートを3306と3307の2インスタンス構築しました。
同一サーバ上のインスタンス間で最低限必要な設定でレプリケーションを構築する例を紹介します。
VirtualBox | 6.1 | |
CentOS | 8.4.2105 | |
MySQL | 8.0.26 | |
MySQL_1号機 | port | 3306 |
datadir | /var/lib/mysql/mysql_3306 | |
socket | /var/lib/mysql/mysql_3306/mysql.sock | |
log-error | /var/log/mysqld_3306.log | |
MySQL_2号機 | port | 3307 |
datadir | /var/lib/mysql/mysql_3307 | |
socket | /var/lib/mysql/mysql_3307/mysql.sock | |
log-error | /var/log/mysqld_3307.log |
5-1 非同期レプリケーション
下記の手順で非同期レプリケーションを構築します。
MySQL_1号機(3306):ソース(マスタ)、MySQL_2号機(3307):レプリカ(スレーブ)
手順1:レプリケーション用パラメータ設定
今回は同一サーバ上に2インスタンス構築しているので、同じmy.cnfにそれぞれのレプリケーションパラメータを追記します。
手順2:ソース(マスタ)側にレプリケーションユーザーを作成
ソース(マスタ)側にレプリカ(スレーブ)側から接続可能なレプリケーションユーザー(repl)を作成します。
今回は、同一サーバ上であるためlocalhostを指定して作成します。
手順3:ソース(マスタ)側からバックアップファイルを取得
ソース(マスタ)側からmysqldumpでバックアップファイルを取得します。
手順4:バックアップファイルをレプリカ(スレーブ)にリストア
ソース(マスタ)側で取得したバックアップファイルをレプリカ(スレーブ)にリストアします。
手順5:レプリカ(スレーブ)側でソース(マスタ)の指定
引き続きレプリカ(スレーブ)側でレプリケーション設定としてソース(マスタ)の情報を設定します。
手順6:レプリケーション開始
レプリカ(スレーブ)側でレプリケーションを開始します。
Slave_IO_Running : スレーブのI/Oスレッドが稼働状況
Slave_SQL_Running : スレーブのSQLスレッドが稼働状況
5-2 準同期レプリケーション
上記で構築した非同期レプリケーション構成を、下記手順で準同期レプリケーション構成に変更します。
手順1:プラグインのインストールと有効化
準同期レプリケーションのプラグインをソース(マスタ)とレプリカ(スレーブ)にそれぞれインストールし、有効化にします。
手順2:I/Oスレッドの再起動
レプリカ(スレーブ)側でI/Oスレッドを再起動し、準同期レプリケーションに切り替えます。
6.おわりに
非同期レプリケーションと準同期レプリケーションの仕組みと、特徴の違いによる使い分け、設定方法について解説しました。
どちらの方式にするかは、何を目的にしたレプリケーションなのかによって選択します。
また、準同期レプリケーションのソース(マスタ)から新たに非同期レプリケーションのレプリカ(スレーブ)を追加し、非同期と準同期を混在させることも可能です。
MySQLでは、システム要件に合わせて複数のレプリカ(スレーブ)を作成することで、負荷分散と冗長化の両方を実現することができます。