Q:マスタがすでに実行中でそれを停止したくない場合、どのようにスレーブをセットアップしますか。
A:いくつかの方法があります。マスタのバックアップを作成してあり、スナップショットに対応するバイナリログ名とオフセットを記録(SHOW
MASTER STATUS
の出力から)してある場合は、以下を実行します。
スレーブに一意のサーバ ID が割り当てられていることを確認する。
各パラメータに適切な値を割り当て、以下のステートメントをスレーブで実行する。
mysql>CHANGE MASTER TO
->MASTER_HOST='master_host-name',
->MASTER_USER='master_user_name',
->MASTER_PASSWORD='master_pass',
->MASTER_LOG_FILE='recorded_log_name',
->MASTER_LOG_POS=recorded_log_pos;
スレーブで START SLAVE
を実行する。
マスタのバックアップがない場合、以下の方法ですばやく確実にスレーブのセットアップを実行できます。
FLUSH TABLES WITH READ LOCK
gtar zcf /tmp/backup.tar.gz
/var/lib/mysql
(または、このバリエーション)
SHOW MASTER
STATUS
(後で必要となるため、出力を必ず記録しておく)
UNLOCK TABLES
代替手段として、上記のバイナリコピーの代わりに、マスタの
SQL
ダンプを使用することもできます。これを行うには、マスタで
mysqldump --master-data
を実行し、後でその SQL
ダンプをスレーブで実行します。ただし、これはバイナリコピーよりも時間がかかります。
2 つの方法のどちらを使用する場合でも、その後、スナップショットがあり、ログ名およびオフセット値を記録する場合の指示に従ってください。同じスナップショットを使用して複数のスレーブをセットアップできます。いったんマスタのスナップショットを作成すれば、マスタのバイナリログが損傷を受けない限り、数日後でも、場合によっては一ヶ月後でもそのスナップショットを使用してスレーブをセットアップできます。理論的には、待機できる時間は無限です。現実的な制約としては、マスタのディスク空き容量が古いログによって減っていくことと、スレーブがマスタに追いつくのに時間がかかることが挙げられます。
LOAD DATA FROM MASTER
を使用することもできます。これはスナップショットを撮り、スレーブにそれをリストアして、スレーブ上のログ名とオフセットを調整することを、全部同時に実行できる便利なコマンドです。将来は、LOAD
DATA FROM MASTER
がスレーブセットアップの推奨方法となります。ただし、このコマンドを使用した場合、読み取りロックが長時間掛かる可能性があります。このコマンドはまだ理想とする効率性では実装されていません。大きなテーブルがある場合、現時点での推奨方法は、FLUSH
TABLES WITH READ LOCK
を実行後のローカル
tar
スナップショットです。
Q: スレーブは常にマスタに接続しておく必要がありますか。
A: いいえ、その必要はありません。スレーブは何時間でも、あるいは何日間でもシャットダウンしておいたり、非接続にしておいても、再接続してマスタの更新に追いつくことができます。たとえば、マスタとスレーブの関係をダイヤルアップリンクでセットアップし、リンクアップを散発的かつ短時間に設定できます。この場合、何か特殊な対策をとらないと、任意の時点でスレーブがマスタと同期されている保証はありません。将来、少なくとも 1 つのスレーブが同期するまでマスタをブロックするオプションを追加する予定です。
Q: スレーブがマスタと比較してどれだけ遅れているかを知るにはどうすればいいですか。つまり、スレーブによってレプリケートされた最後のクエリの日付を知る方法はありますか。
A: スレーブが 4.1.1
以降の場合は、SHOW SLAVE STATUS
の
Seconds_Behind_Master
カラムを参照します。これより前のバージョンについては、次のようになります。スレーブ
SQL スレッドが存在する場合、つまりSHOW
PROCESSLIST
で表示される場合(MySQL 3.23
では、スレーブスレッドが存在する場合、つまりスレーブスレッドが
SHOW PROCESSLIST
で表示される場合)(see
項4.11.3. 「レプリケーションの実装の詳細」)、およびそのスレッドがマスタから読み取ったイベントを最低
1
回は実行している場合のみ、スレーブによってレプリケートされた最後のクエリの日付を知ることができます。実際、スレーブ
SQL
スレッドがマスタから読み取ったイベントを実行すると、このスレッドは自分の時間をそのイベントのタイムスタンプに修正します(これが、TIMESTAMP
もレプリケートする理由です)。結果、SHOW
PROCESSLIST
出力の Time
カラムでスレーブ SQL
スレッドに対して表示される秒数は、最後にレプリケートされたイベントのタイムスタンプとスレーブマシンの実際の時刻の差になります。これを使用して、最後にレプリケートされたイベントの日付を特定できます。注意:
スレーブがマスタから切断されて 1
時間経過してから再接続した場合、SHOW
PROCESSLIST
の Time
カラムでスレーブ SQL スレッドが 3600
の値を表示する場合があります。これは、スレーブが実行しているクエリが、タイムスタンプから
1 時間経過しているためです。
Q: スレーブが追いつくまでマスタの更新をブロックするにはどうしますか。
A: 以下の手順を実行します。
マスタで、以下のコマンドを実行する。
mysql>FLUSH TABLES WITH READ LOCK;
mysql>SHOW MASTER STATUS;
SHOW
ステートメントの出力からログ名とオフセットを記録する。
スレーブで以下のコマンドを実行する。ここで、MASTER_POS_WAIT()
関数の引数であるレプリケーション座標は、前のステップで記録した値。
mysql> SELECT MASTER_POS_WAIT('log_name', log_offset);
指定のログファイルおよびオフセットにスレーブが到達するまで、SELECT
ステートメントによってブロックされる。到達した時点でスレーブはマスタと同期しており、こここでステートメントが戻る。
マスタで以下のステートメントを発行し、マスタによる更新処理の再開を許可する。
mysql> UNLOCK TABLES;
Q: 二方向レプリケーションをセットアップするときに注意すべき点はありますか。
A: MySQL レプリケーションでは、現在のところ、分散(サーバ間の)更新の原子性を保証するためのマスタとスレーブ間のロッキングプロトコルをサポートしていません。つまり、クライアント A が co-master 1 に更新を行い、それを co-master 2 に伝播する前に、クライアント B が co-master 2 に更新を行って、クライアント A の更新が co-master 1 で行ったものとは変わってしまう可能性があります。この場合、co-master 2 からの更新がすべて伝播した後であっても、クライアント A の更新が co-master 2 に伝わったとき、co-master 1 とは異なるテーブルが生成されます。このため、どのような順序でも更新が安全に行われるという確証がある場合、またはクライアントコードで更新順序の不正に対処できる場合以外は、二方向レプリケーションで 2 つのサーバをチェーン状に設定しないでください。
また更新については、二方向レプリケーションはそれほどパフォーマンス向上に役立たないことも認識してください。サーバは両方ともそれぞれ、1 つのサーバのときと同じ量の更新を行います。違いは、別のサーバから発生した更新が 1 つのスレーブスレッドでシリアル化されるため、ロックの競合が少なくなることぐらいです。その利点も、ネットワーク遅延によって相殺されてしまいます。
Q: レプリケーションを使用してシステムのパフォーマンスを改善する方法はありますか。
A: 1
つのサーバをマスタとしてセットアップし、すべての書き込みをそれにダイレクトします。そして予算とスペースが許容する限り多くのスレーブをセットアップし、マスタと複数のスレーブで読み取りを分散します。--skip-bdb
、--low-priority-updates
、および
--delay-key-write=ALL
でスレーブを起動すると、スレーブの速度が向上します。この場合、スレーブは速度を上げるため、BDB
テーブルの代わりに非トランザクションの
MyISAM
テーブルを使用します。
Q: パフォーマンス改善レプリケーションを使用するアプリケーションを作成したいのですが、クライアントコードはどうすればいいですか。
A: コード内のデータベースアクセスを担当する部分が適切に抽象化つまりモジュール化されていれば、レプリケートのセットアップで実行できるように変換するのはスムーズかつ簡単です。データベースアクセスの実装部分を変更し、すべての書き込みをマスタに、そして読み取りをマスタかスレーブに送信するようにします。ご使用のコードにこのレベルの抽象化がなされていなければ、レプリケーションシステムを 1 からセットアップします。まず以下の関数で、ラッパライブラリまたはモジュールを作成します。
safe_writer_connect()
safe_reader_connect()
safe_reader_query()
safe_writer_query()
各関数名の safe_
は、関数がすべてのエラー条件を処理することを意味します。もちろん、関数には別の名前を使用することも可能です。重要なことは、読み取りのための接続、書き込みのための接続、読み取り実行、および書き込み実行で統合インタフェースを持つことです。
次に、ラッパライブラリを使用するようにクライアントコードを変換します。このプロセスは最初は苦痛かもしれませんが、長期的に見ると損はありません。先ほど説明したアプローチを使用するアプリケーションはすべて、マスタ/スレーブ構成の利点を活用できます。これは、スレーブが複数の場合でも同様です。コードは保守が非常に簡単で、トラブルシューティングオプションの追加も手間がかかりません。1 つか 2 つの関数を修正するだけで、各クエリにかかった時間をログしたり、数千のクエリの中からどのクエリがエラーの原因になったかを特定することなどができます。
コード作成の経験が豊富であれば、replace
ユーティリティを使用して変換タスクを自動化することもできます。このユーティリティは
MySQL
の標準ディストリビューションに含まれています。また、独自の
Perl スクリプトを作成することもできます。
コードが認識可能なパターンに従っていれば理想的です。そうでない場合は、書き換えるのが良いでしょう。あるいは少なくとも、1
つのパターンになっているようにしてください。
Q: MySQL レプリケーションによって、どのような場合にどれだけシステムのパフォーマンスを改善できますか。
A: MySQL レプリケーションは、読み取り頻度が高く、書き込み頻度が低いシステムで最も威力を発揮します。単一マスタと複数スレーブのセットアップを使用することにより、理論的にはネットワーク帯域幅の限界またはマスタが処理できる更新負荷の限界までスレーブを追加することにより、システムを拡張できます。
追加する利点がなくなるまでいくつのスレーブを追加できるか、またサイトのパフォーマンスをどれだけ改善できるかを判断するには、クエリパターンを知り、実証的に(ベンチマークを使用して)通常のマスタと通常のスレーブの間の読み取り(毎秒ごとの読み取り、または
max_reads
)と書き込みスループットの関係を調べる必要があります。ここでは、例として、仮想システムのレプリケーションでの単純化した計算を示します。
システム負荷が 10% の書き込みと 90%
の読み取りで構成され、max_reads
が 1200 - 2 * max_writes
であると仮定します。
つまり、書き込みがなければシステムは毎秒
1200
の読み取りを実行できます。書き込みの平均は読み取り平均の
2
倍かかります。そしてその関係は直線的です。
マスタと各スレーブの能力は同じで、1
マスタと N
スレーブがあると想定します。各サーバ(マスタまたはスレーブ)は以下のようになります。
reads = 1200 - 2 *
writes
(ベンチマークから)
reads = 9* writes / (N + 1)
(読み取りは分散されるが、書き込みはすべてのサーバで行われる)
9*writes/(N+1) + 2 * writes = 1200
writes = 1200/(2 + 9/(N+1)
この分析により、以下の結論を導きだせます。
N = 0(レプリケーションがないことを意味する)の場合、システムは 1200/11、つまり毎秒 109 書き込みを処理できる(アプリケーションの性質上、読み取りが 9 倍になる)。
N = 1 の場合、毎秒 184 の書き込みまで処理できる。
N = 8 の場合、毎秒 400 の書き込みまで処理できる。
N = 17 であれば、480 の書き込みとなる。
N が無限に近づくと(予算も無限大に膨らむが)、毎秒 600 の書き込みに近くなり、システムスループットは 5.5 倍になる。しかし、8 サーバだけで 4 倍近くになっている。
注意: この計算ではシステム帯域を無限として想定しており、現実の場面では重要となるかもしれない要因をいくつか無視しています。多くの場合、N アプリケーションスレーブを追加した場合の結果を正確に予測する上記のような計算を行うのは難しいと言えます。しかし、以下の質問から、レプリケーションによってシステムのパフォーマンスが改善されるかどうか、またどの程度改善されるか、ある程度判断できるでしょう。
システムの読み取りと書き込みの比率はどれくらいか。
読み取りを減らした場合、1 つのサーバで処理できる書き込み負荷をどの程度増やせるか。
ネットワークの帯域幅を使用できるスレーブ数の上限はいくつか。
Q: 冗長性と高可用性を実現するようにレプリケーションを使用するにはどうすればよいですか。
A: 現在使用可能な機能で、1 つのマスタと 1 つのスレーブ(または複数のスレーブ)をセットアップする必要があります。そして、マスタの稼働状態を監視し、失敗時にアプリケーションとスレーブにマスタの変更を指示するスクリプトを作成します。以下のガイドラインを参考にしてください。
スレーブにマスタを変更するよう指示するには、CHANGE
MASTER TO
コマンドを使用する。
アプリケーションにマスタの場所を認識させておくためには、マスタに動的
DNS
エントリを採用すると良い。bind
で、nsupdate
を使用して DNS
を動的に更新できる。
--log-bin
オプションを指定し、--log-slave-updates
なしでスレーブを実行する。STOP
SLAVE
および RESET MASTER
を実行し、他のスレーブで CHANGE MASTER
TO
を実行することにより、スレーブがマスタになる準備ができる。たとえば、以下のセットアップがあると仮定する。`M''
はマスタ、``S'' はスレーブ、``WC''
はデータベース読み取りおよび書き込みを発行するクライアントを意味する。データベース読み取りだけを発行するクライアントは、切り替えの必要がないため、ここでは考慮されていない。
WC \ v WC----> M / | \ / | \ v v v S1 S2 S3
S1(S2 および S3
と同様)は、--log-bin
を使用し、--log-slave-updates
なしで実行しているスレーブである。S1
で実行される書き込みは M
からのレプリケーションのみなので、S1
のバイナリログは空白である(S1
は --log-slave-updates
なしで実行されている)。 何らかの理由で M
が利用できなくなったため、S1
を新しいマスタにする(すべての WC を S1
にダイレクトし、S2 と S3 が S1
をレプリケートするように設定する)。
すべてのスレーブで、自身のリレーログにあるすべてのクエリを処理したことを確認する。各スレーブで
STOP SLAVE IO_THREAD
を発行し、SHOW PROCESSLIST
の出力で Has read all relay log
が表示されることを確認する。すべてのスレーブでこれを確認したら、新しい環境に設定できる。すべてのスレーブで
STOP SLAVE
を発行し、マスタに昇格するスレーブに
RESET MASTER
を、他のスレーブには CHANGE
MASTER
を実行する。
これで、M にアクセスする WC
はいなくなる。すべての WC に、クエリを S1
に送信するよう指示する。これ以降、WC
によって S1 に送信されたクエリはすべて、S1
のバイナリログに書き込まれる。S1
のバイナリログには、M
が終了した時点以降に S1
に送信されたクエリがすべて正確に含まれる。
S2(および S3)で、STOP
SLAVE
、CHANGE MASTER TO
MASTER_HOST='S1'
を実行する('S1'
には S1
の実際のホスト名が入る)。CHANGE
MASTER
で、S2 または S3 から S1
に接続するための全情報(ユーザ、パスワード、ポート)を追加する。CHANGE
MASTER
で、S1
のバイナリログの名前や位置を指定する必要はない。それが最初のバイナリログであり、位置が
4 であることがわかっており、これらの値は
CHANGE MASTER
のデフォルトとなっているからである。最後に、S2
と S3 で START SLAVE
を実行すると、以下のようになる。
WC / | WC | M(unavailable) \ | \ | v v S1<--S2 S3 ^ | +-------+
M が再稼動したら、S2 および S3 と同じように
CHANGE MASTER
を実行するだけで済む。そうすると M は S1
のスレーブとなり、ダウンしてから実行された
WC 書き込みをすべてピックアップする。M
をマスタに戻す(それが一番強力なマシンである、という理由などで)には、S1
と M
の立場を逆にして前回の手順を繰り返す。このとき、S1、S2、S3
を M のスレーブにする前に、M で RESET
MASTER
を実行することを忘れてはいけない。そうしないと、M
が非稼動になる前の古い WC
書き込みも拾ってしまう。
現在、自動マスタ選択システムを MySQL に統合する方向で進んでいますが、それが実現するまでは、自分で監視ツールを作成してください。
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.