データベースサーバは共同して稼動できます。 その目的は、最初のサーバが故障したとき次のサーバへ速やかに引き継ぎができること(高可用性)および複数のコンピュータが同一のデータを処理できること(負荷分散)です。 データベースサーバがシームレスに共同稼動できれば理想的です。 静的なウェブページを提供するウェブサーバは、ウェブからの要求で生ずる負荷を複数のマシンに分散するだけで、簡単に結合できます。 実際、読み取り専用のデータベースサーバの結合は、同じようにかなり容易です。 しかし、大部分のデータベースサーバは、読み書きの混在した要求を受け取り、読み書き両用のサーバの結合はとても困難です。 なぜなら、読み取り要求だけの場合、全サーバへのデータの配布は 1回で終わります。 しかし、書き込み後の読み取り要求に対して一貫性のある結果を返すためには、書き込み要求を受けたサーバだけでなく、他の全サーバにおいてもデータに書き込まなければなりません。
この同時性を持たせるという問題は、共同して稼動するサーバにおいて根本的に困難なものです。 全ての使用状況において、単一の解法を用いて同時性の問題の影響を軽減できないため、複数の解法が存在します。 各々の解法はこの問題に異なったやり方を適用し、固有の作業負荷に対する影響を最小化します。
幾つかの解法では、1つのサーバだけにデータの更新を許可することにより、同時性を持たせています。 データの更新ができるサーバを、読み書きサーバまたはマスタサーバといいます。 読み取り専用の問い合わせだけに応答できるサーバを、スレーブサーバといいます。 マスタサーバが変更されるまでは、利用者がアクセスできないサーバを、スタンバイサーバといいます。
同期を取ることは解法の一種です。 すなわち、データに書き込むトランザクションでは、全サーバがコミットするまでトランザクションはコミットされません。 これによって、フェールオーバにおいてデータの消失がないことが保証されます。 また、どのサーバが問い合わせを受理したかに関係なく、全ての負荷分散サーバが一貫した結果を返すことが保証されます。 それに対して非同期の解法では、コミット時刻と他サーバへの伝達時刻に時間差がありうるため、バックアップサーバへ交代する時にトランザクションが消失する可能性があります。 また、負荷分散サーバにおいては、最新でない結果を応答する可能性があります。 サーバ間の非同期の通信は、同期によって大きく遅れそうなとき使用されます。
解法は処理する範囲によって分類することもできます。 ある解法ではデータベースサーバ全体だけを範囲として処理しますが、他の解法では各テーブルまたは各データベースを範囲として管理できます。
全ての選択において、作業効率を考えなければなりません。 通常、作業効率と機能性は相反する関係にあります。 例えば、遅いネットワークの場合、完全同期の解法を使えば作業効率は半分以下となりますが、非同期の解法を使えば作業効率への影響が最小となります。
本節では、フェールオーバとレプリケーションと負荷分散における種々の解法を説明します。 glossaryも利用できます。
データベースのコピーを 1つだけ保有すればよいため、共有ディスクを用いたフェールオーバは同期によるオーバーヘッドを回避できます。 本解法では、複数のサーバが単一のディスクアレイを共有します。 主データベースサーバが故障したとき、まるでデータベースの破損から回復したように、スタンバイサーバが元のデータベースを実装して稼動できます。 このフェールオーバは急速であり、データの消失がありません。
ハードウェアを共有するという機能は、ネットワーク上の記憶装置に共通のものです。 ネットワークのファイルシステムの利用も可能ですが、そのファイルシステムが POSIX 仕様(各 UNIX 間の互換性の仕様)を満たしているか注意してください。 ( 項17.2.1を見てください)。 本解法には重大な制約があり、共有ディスクアレイが故障または破損したとき、主サーバもスタンバイサーバも機能しなくなります。 また、主サーバが稼動している間は、スタンバイサーバが共有記憶装置にアクセスしてはなりません。
ハードウェアを共有するという機能の改良版が、ファイルシステムのレプリケーションであり、ファイルシステムにおける全ての変更が別のコンピュータに設置したファイルシステムに反映されます。 制約はただ一つであり、スタンバイサーバがファイルシステムの一貫性のあるコピーを確保するようにミラーリングしなければなりません。 特に、スタンバイサーバへの書き込みは、マスタサーバへの書き込みと同じ次元で行わなければなりません。 Linux におけるDRBDは、ファイルシステムのレプリケーションの一般的な解法です。
ウォームスタンバイサーバ(項24.4を参照)は、ログ先行書き込み(WAL)を解読して最新の状態を保持できます。 主サーバが故障したとき、ウォームスタンバイサーバが主サーバのほぼ全てのデータを保存して、速やかに新しい主データベースを稼動できます。 本解法は非同期であり、データベース全体だけを範囲として処理できます。
マスタとスレーブによるレプリケーションでは、データ更新の全ての問い合わせをマスタサーバに送付します。 マスタサーバは更新したデータを非同期でスレーブサーバに送付します。 マスタサーバが稼動している間、スレーブサーバは読み取り問い合わせだけに応答します。 スレーブサーバはデータウェアハウスへの問い合わせに理想的です。
この種類のレプリケーションの一例はSlony-Iであり、各々のテーブルが処理する範囲となり、複数のスレーブサーバが稼動できます。 バッチ処理によってスレーブサーバのデータを非同期で更新するため、フェールオーバにおけるデータ消失の可能性があります。
文に基づいたレプリケーションのミドルウェアでは、プログラムが全ての SQL 問い合わせを採取して、1つまたは全てのサーバに送付します。 なお、各々のサーバは独立して稼動します。 読み書き問い合わせは全サーバに送付しますが、読み取り問い合わせは作業負荷を分散させるために、1つのサーバだけに送付できます。
問い合わせを修正しないで送付した場合、関数 random()
による乱数値と関数 CURRENT_TIMESTAMP
による現在時刻およびシーケンス値が、サーバごとに異なることがあります。
その理由は、各サーバが独立して稼動しているため、および SQL 問い合わせの送付では、実際に更新した行の識別値を取得できないためです。
これが許容できない場合は、ミドルウェアかアプリケーションにおいて 1つのサーバにこのような問い合わせを送付し、その結果を書き込み問い合わせで使用しなければなりません。
また、トランザクションをコミットするか中断するかについても、全サーバが同一となるよう注意しなければなりません。
これには 2相コミット(PREPARE TRANSACTION および COMMIT PREPARED)を使用することになるでしょう。
Pgpool-IIとSequoiaがこのレプリケーションの一例です。
ラップトップやリモートマシンのように、通常は接続されていないサーバ間において、データの一貫性を保持することは挑戦的な課題です。 非同期マルチマスタレプリケーションの使用により、全サーバの独立した稼動、およびトランザクションの衝突を識別するための定期的な通信を実現します。 トランザクションの衝突は、利用者および衝突回避法によって解決できるでしょう。 Bucardoはこの種のレプリケーションの一例です。
同期マルチマスタレプリケーションでは、全てのサーバは書き込み要求を受理できます。
受理サーバは更新したデータを、トランザクションをコミットする前に、他の全サーバへ配布します。
書き込み負荷が重いとき、ロックの掛かり過ぎによる作業効率の低下の原因となりえます。
実際、書き込み効率は単一サーバより悪いことが大半です。
読み取り要求はどのサーバにも送付できます。
通信による負荷を減らすには、共有ディスクが実装されます。
同期マルチマスタレプリケーションは、主に読み取り作業負荷の低減に最適ですが、全てのサーバが書き込み要求を受理できることも大きな利点です。
その利点とは、マスタとスレーブ間で作業負荷を分けなくてよいこと、および更新データが 1つのサーバから他のサーバに送付されるため、出力が確定しない random()
関数などによる問題が起こらないことです。
PostgreSQL では、この種類のレプリケーションを提供しません。 しかし、PostgreSQL の 2相コミット(PREPARE TRANSACTION および COMMIT PREPARED)を使用すれば、アプリケーションのコードまたはミドルウェアにおいて本解法を実装できます。
PostgreSQL はオープンソースであり、容易に拡張できます。 そのため多数の企業が、PostgreSQL を取り入れて商業的な解法を作成し、フェールオーバとレプリケーションと負荷分散の機能を独自に実現していますが、ソースコードは非公開です。
表(表25-1)は、上述した種々の解法の性能を抜粋したものです。
表 25-1. 高可用性、負荷分散およびレプリケーションの特徴
特徴 | 共有ディスクを用いたフェールオーバ | ファイルシステムのレプリケーション | PITR を用いたウォームスタンバイ | マスタとスレーブによるレプリケーション | 文に基づいたレプリケーションのミドルウェア | 非同期マルチマスタレプリケーション | 同期マルチマスタレプリケーション |
---|---|---|---|---|---|---|---|
最も一般的な実装 | NAS | DRBD | PITR | Slony | pgpool-II | Bucardo | |
通信方法 | 共有ディスク | ディスクブロック | WAL | テーブル行 | SQL | テーブル行 | テーブル行および行ロック |
特別なハードウェアが不要 | ○ | ○ | ○ | ○ | ○ | ○ | |
複数のマスタサーバが可能 | ○ | ○ | ○ | ||||
マスタサーバにオーバヘッドがない | ○ | ○ | ○ | ||||
マスタサーバに待機がない | ○ | ○ | ○ | ○ | |||
マスタの故障によるデータ損傷がない | ○ | ○ | ○ | ○ | |||
スレーブは読み取り問い合わせだけを受理 | ○ | ○ | ○ | ○ | |||
処理する範囲がテーブルと同じ | ○ | ○ | ○ | ||||
トランザクションの衝突の回避が不要 | ○ | ○ | ○ | ○ | ○ |
上の分類に該当しない解法もあります。
データの分割とは、同じテーブルのデータを複数部分に分けることです。 各部分に書き込むことができるのは、1つのサーバだけです。 例えば、データをロンドンとパリの営業所用に分割でき、サーバをロンドンとパリのどちらにも設置できた状態を考えます。 問い合わせにロンドンとパリのデータが混在した場合、アプリケーションは両方のサーバに問い合わせることができます。 または、マスタスレーブレプリケーションを使用して、他の営業所のデータを読み取り専用コピーとして保持できます。
上述した多くの解法は、複数のサーバが複数の問い合わせを処理するものです。 処理速度の向上のために、単一の問い合わせに複数のサーバを使用するものはありません。 本解法は複数のサーバが単一の問い合わせを共同して実行するものです。 その方法は、データをサーバ間で分割し、各サーバが部分的に問い合わせを実行し、各々の結果を主サーバに送付し、主サーバが合体して利用者に返送するものです。 Pgpool-IIはこの性能を持っています。 また、PL/Proxyツールセットを使用して実装できます。