レプリケーション利用時の注意点
PostgreSQLレプリケーションの「同期」は、WALの伝播を同期するだけで、テーブルへのデータ反映は非同期で行われます。そのため同期・メモリ同期を選択したとしても、更新直後にスレーブからデータを参照すると、更新の反映がまだ行われていない場合があります[3]。
また前節で紹介した4つの設定は性能と可用性がトレードオフの関係にあります。それぞれの特徴は以下のとおりです。
同期はユーザへの応答があった時点でマスター・スレーブの両方のディスクにWALが書き込まれます。スレーブのディスクに最新の更新が存在しますので、マスターのディスク障害が発生しても最新の更新が失われることはありません。しかし、スレーブでのWAL書き込みを待つため、他の設定に比べて更新処理のレスポンス時間が長く、性能面で劣ります。
メモリ同期はユーザへの応答があった時点でマスターのディスクとスレーブのメモリにWALが書き込まれます。スレーブのメモリに最新の更新が存在しますので、マスターのディスク障害が発生しても最新の更新が失われません。WAL書き込みを待つのはスレーブのメモリへの書き込み時点までであるため、ディスクI/Oを待たない分、同期設定に比べて更新処理のレスポンスが早いです。
スレーブ非同期ではマスターのディスクへのWAL書き込みは待ちますが、スレーブへの書き込みを待たずにユーザへ応答します。このため、スレーブに最新の更新が完了していない可能性があり、もしマスターがディスク障害を起こしたとき、最新の更新が失われる恐れがあります。しかしスレーブへの書き込みを待たないので更新処理レスポンスは高速です。
完全非同期はWALの書き込みを待たず、最新のWALはマスターのメモリ上にのみあります。もしマスターが何らかの障害を起こした場合、マスターのメモリから最新の更新が消えてしまい、更新内容を失う可能性があります。そのため本番では利用すべきではありません。ただし、ディスクへの書き込みを待たないので更新処理レスポンスは非常に高速です。今回は他の設定との性能比較のために利用します。
さらに、PostgreSQL 9.2ではマスター1台スレーブ1台のレプリケーション構成で同期/メモリ同期を採用した場合、スレーブへのWAL書き込みをマスターがタイムアウトせずに待つ仕様になっています。このためスレーブの障害の発生がマスターがスレーブへのWAL書き込み待ちと同じタイミングの場合、マスターの処理も停止し、クライアントへ処理結果が返りません。つまりスレーブが単一障害点です(図2)。
そのため、私たちは同期・メモリ同期を採用する場合にはスレーブを複数台用意して、最低3台構成にすることを推奨しています。3台構成の場合、スレーブは自動的に同期スレーブと非同期スレーブになり、同期スレーブの障害時には非同期スレーブが同期スレーブに自動で格上げされます[4][5]。設定方法は以下のようにマスターのpostgres.confのsynchronous_standby_namesにスレーブのrecovery.confに設定したapplication_nameへホスト名をカンマ区切りで記述します。
synchronous_standby_names = 'slave_hostname1,slave_hostname2'
注意点をまとめると以下の表になります。
設定名 | 性能 | 可用性 |
---|---|---|
同期 | 性能が最も劣化しやすい |
マスターのディスク障害時も最新のCOMMIT済データを 失わないが、2台構成ではスレーブが単一障害点 |
メモリ 同期 |
性能が劣化しやすい (同期よりは劣化しにくいはず) |
マスターのディスク障害時も最新のCOMMIT済データを 失わないが、2台構成ではスレーブが単一障害点 |
スレーブ 非同期 |
性能が劣化しにくい |
マスターのディスク障害時に 最新のCOMMIT済データを失う可能性あり |
完全 非同期 |
性能が最も劣化しにくい |
マスターの障害時に最新のCOMMIT済データを失う可能性あり (本番環境では使用するべきではない) |
このように設定によって特性が違うため、システム全体の特徴に応じて、可用性重視なら「同期/メモリ同期」、性能重視なら「スレーブ非同期」というように、どの設定を採用するかを注意深く選択し使い分ける必要があります。
レプリケーション設定の違いに対する性能比較検証
ここからはレプリケーション設定の違いでマスターの性能がどの程度違うか、簡単な比較検証を行います。
今回は図3の環境で検証を行いました。
3台のPostgreSQLサーバーのうち、1台をマスター、2台をスレーブとして稼働させ、PostgreSQL 9.2.3に同梱されているベンチマークツールpgbenchを使い、負荷をかけた時のスループットとレスポンスを計測します。また、pgbenchから発行されたクエリーはすべてマスターに送信されます。
今回は追検証できるようにAWSを使用しました。
インスタンスタイプ | c1.midium |
---|---|
CPU |
同期スレーブ:Intel Xeon E5506 x 2、 非同期スレーブ:Intel Xeon E5-2650 x 2もしくはIntel Xeon E5506 x 2 |
HDD(EBS) | 8GB(スタンダードボリューム) |
非同期スレーブのCPUスペックが複数あるのはAWSでは同じインスタンスタイプでもさまざまなリソースが混在しているためです。今回の検証ではその影響を受けないようにCPUのばらつきを非同期スレーブに集めました。
安定して負荷がかかるようにpostgres.confに以下の設定を入れました。
max_connections = 300 shared_buffers = 256MB work_mem = 2MB checkpoint_segments = 64 wal_keep_segments = 32 effective_cache_size = 256MB
また、データとWALの書込は同一のHDD(EBS)です。