5.3. クラスタリングモード

backend_clustering_mode (enum)

クラスタリングモードはPostgreSQLの同期を取る方法を指定します。 クラスタリングモードの設定にはbackend_clustering_modeを使用します。 この節ではクラスタリングモードの設定方法を説明します。 詳細は項2.1.1をご覧ください。

5.3.1. ストリーミングレプリケーションモード

このモードはもっともよく使われており、推薦できるクラスタリングモードです。 このモードではPostgreSQLが個々のサーバをレプリケーションします。 このモードを有効にするにはbackend_clustering_modeに'streaming_replication'を設定してください。

backend_clustering_mode = 'streaming_replication'
    

このモードでは127台までのストリーミングレプリケーションスタンバイサーバを使用できます。 また、スタンバイサーバをまったく使用しないことも可能です。

このモードの難点は、検索問い合わせを負荷分散させた時に、スタンバイサーバのレプリケーション遅延を意識しなければならない点です。 ノードをまたがる可視性の一貫性も保証されません。 この問題を改善するために多くの追加パラメータが用意されていますが、そのことが管理を難しくする場合もあります。 また、プライマリサーバがダウンしてスタンバイが昇格する場合にフェイルオーバの時間がかかることがあります。 こうした問題を避けたい場合は、スナップショットアイソレーションモードをご検討ください。

ストリーミングレプリケーションモードで使用する追加のパラメータについては項5.11をご覧ください。

5.3.2. ネイティブレプリケーションモード

このモードではPostgreSQL間のデータレプリケーションをPgpool-IIに行わせます。 このモードを有効にするにはbackend_clustering_modeに'native_replication'を設定してください。

backend_clustering_mode = 'native_replication'
    

このモードでは127台までのレプリカサーバを使用できます。 また、レプリカサーバをまったく使用しないことも可能です。

参照負荷をバックエンドノードに振り分ける負荷分散(項5.7を参照)もレプリケーションモードと共に使用可能です。

このモードの難点は、ノードをまたがる可視性の一貫性が保証されないことです。 このことでノードの間のデータの一貫性が崩れたり、一貫性のないデータを一時的に読み込んでしまうことがあります。 こうした問題を避けたい場合は、スナップショットアイソレーションモードをご検討ください。

以下のオプションがレプリケーションモードにおけるPgpool-IIの動作に影響します。

replication_stop_on_mismatch (boolean)

これがonで、全てのPostgreSQLバックエンドノードに送られたクエリに対して、全てのノードが同じパケット種類で応答しなかった場合、多数派とは異なる応答したバックエンドノードはPgpool-IIにより切り離されます。 replication_stop_on_mismatchがoffの場合に同様の状況が発生したときには、Pgpool-IIは現在のユーザセッションを強制終了するだけにとどめ、バックエンドの切り離しは行いません。

注意: Pgpool-IIはバックエンドから返されたデータは調べずに、結果パケットの種類の比較のみにより決断します。

replication_stop_on_mismatchを有効にする典型的なユースケースは、バックエンドノード間のデータ不整合の防止です。 例えば、UPDATE文が他のノードでは成功しているのにあるバックエンドノードでは失敗した場合、そのバックエンドノードを切り離したいかもしれません。

デフォルトはoffです。

このパラメータはPgpool-IIの設定を再読み込みすることで変更可能です。

failover_if_affected_tuples_mismatch (boolean)

これがonで、全てのノードの応答でINSERT/UPDATE/DELETEクエリの影響を受けたタプルの数が同じでなかった場合、多数派とは異なる応答したバックエンドノードはPgpool-IIによる切り離されます。 failover_if_affected_tuples_mismatchがoffの場合に同様の状況が発生したときには、Pgpool-IIは現在のユーザセッションを強制終了するだけにとどめ、バックエンドの切り離しは行いません。

注意: もし同票で、2つ以上のグループで同じノード数だった場合は、メインノード(最も若いDBノード番号のバックエンドノード)を含むグループが優先されます。

デフォルトはoffです。

このパラメータはPgpool-IIの設定を再読み込みすることで変更可能です。

replicate_select (boolean)

onを設定すると、Pgpool-IIはSELECTクエリのレプリケーションモードを有効にします。 すなわち、SELECTクエリが全てのバックエンドノードに送信されます。

表 5-1. replicate_selectとload_balance_modeがSELECTのルーティングに与える影響

replicate_selectがtrueYN
load_balance_modeがtrueANYYN
SELECTがトランザクションブロックの内部にあるANY Y NANY
トランザクション分離レベルがSERIALIZABLEで、トランザクションが更新クエリを発行済 ANYYNANYANY
結果(R:レプリケーション、M:メインのみに送信、L:負荷分散) RMLLM

デフォルトはoffです。

このパラメータはPgpool-IIの設定を再読み込みすることで変更可能です。

insert_lock (boolean)

onに設定すると、Pgpool-IIはINSERT文が発行される前にPostgreSQL上のテーブルを自動的にロックします。

SERIAL型を使っているテーブルをレプリケーションすると、SERIAL型の列の値がDBノードの間で一致しなくなることがあります。 この問題の回避策は、INSERT実行前に該当テーブルを明示的にロックすることです。

テーブルの自動ロックのため、Pgpool-IIは以下の変換を行います。

       INSERT INTO ...
      

これを次のように変換します。

       BEGIN;
       LOCK TABLE ...
       INSERT INTO ...
       COMMIT;
      

注意

この方法はトランザクションの並列実行性を大きく劣化させます。

Pgpool-II V2.2以降では、テーブルがSERIAL列を持つかどうか自動判別するため、SERIAL列がなければ決してテーブルをロックしません。

Pgpool-II V3.0.4までのPgpool-II V3.0では、テーブルロックではなくシーケンステーブルに対して行ロックをかけます。 これはVACUUM(autovacuumを含む)とのロック競合を最小化することを意図しています。 しかし、これは他の問題を引き起こします。 トランザクション周回が起きた後、シーケンステーブルに対する行ロックはPostgreSQLの内部エラー (詳細には、トランザクション状態を保持するpg_clogへのアクセスエラー)を起こします。 これを防ぐため、PostgreSQLのコア開発者はシーケンステーブルに対する行ロックを許可しないことを決定しました。 これはもちろんPgpool-IIを動作不能にします(修正されたPostgreSQLはバージョン 9.0.5, 8.4.9, 8.3.16そして8.2.22としてリリースされました)。

Pgpool-II V3.0.5以降では、新しいPostgreSQLがシーケンステーブルに対するロックを許可しなくなったため、pgpool_catalog.insert_lockテーブルに対して行ロックをかけます。 したがって、Pgpool-II経由でアクセスするすべてのデータベースにinsert_lockテーブルをあらかじめ作成しておく必要があります。 詳細は項2.8をご覧ください。 もし、insert_lockテーブルが存在しない場合は、挿入対象のテーブルに対してロックを行います。 これは、Pgpool-II V2.2V2.3シリーズと同じ動作です。

過去のバージョンと互換性のあるinsert_lockを使用したい場合は、configureスクリプトでロック方法を指定できます。 詳細は項2.5をご覧下さい。

(文ごとの)細かい制御:

  • insert_lockをtrueにして、テーブルロックを獲得してほしくないINSERT文には、先頭に/*NO INSERT LOCK*/コメントを追加します。

  • insert_lockをfalseにして、テーブルロックを獲得してほしいINSERT文には、先頭に/*INSERT LOCK*/コメントを追加します。

注意: insert_lockを有効にしてregression testを実行すると、PostgreSQL 8.0では transactions, privileges, rules, alter_tableがfailします。

その理由は、ruleテストでPgpool-IIがビューにLOCKを実行しようとするため、そして以下のエラーメッセージが出てしまうためです。

	! ERROR: current transaction is aborted, commands ignored until
	end of transaction block
       

たとえば、transactionsテストでは、存在しないテーブルに対してINSERTを試みており、Pgpool-IIPostgerSQLにそのテーブルのロックを獲得させることになります。 これはもちろんエラーとなります。 トランザクションがアボート状態になり、続くINSERTでは上記エラーが出てしまいます。

デフォルトはonです。

このパラメータはPgpool-IIの設定を再読み込みすることで変更可能です。

lobj_lock_table (string)

ラージオブジェクトのレプリケーションを行いたいときにロック管理に使うためのテーブル名を指定します。 このテーブルが指定されている場合、Pgpool-IIは、lobj_lock_tableで指定されているテーブルをロックした後、pg_largeobjectシステムカタログを参照してラージオブジェクトIDを生成し、lo_create()を呼び出してラージオブジェクトの作成を行います。 この方法により、レプリケーションモードにおいてPgpool-IIが全てのDBノードで同じラージオブジェクトIDを得られることが保証されます。

注意: PostgreSQL 8.0以前はlo_createを持たないため、PostgreSQL 8.0以前のバージョンではこの処理は行われません。

libpqの関数lo_creat()の呼び出しがこの機能の契機となります。 Java API(JDBCドライバ)、PHP API(pg_lo_create、またはPDOといったPHPライブラリの同様のAPI)、様々なプログラミング言語の同様のAPIを経由したラージオブジェクトの生成においても同じプロトコルが使われることがわかっているので、この機能は動作するはずです。

この機能はラージオブジェクトに対する以下の操作では動作しません。

  • lo_createlo_import_with_oidを使う全てのAPI。

  • バックエンドのlo_import関数をSELECTで呼び出す場合

  • バックエンドのlo_create関数をSELECTで呼び出す場合

注意: 全てのPostgreSQLユーザはlobj_lock_tableへ書き込み可能である必要が有ります。 また、これはどのスキーマに作成されてもかまいません。

ラージオブジェクトロックテーブルを作る例を示します。

       CREATE TABLE public.my_lock_table ();
       GRANT ALL ON public.my_lock_table TO PUBLIC;
      

デフォルトは''(空文字列)で、この機能は無効です。

5.3.3. スナップショットアイソレーションモード

このモードは、ネイティブレプリケーションモードと似ていますが、更にノードをまたがる可視性の一貫性を保証します。 実装は研究論文Pangea: An Eager Database Replication Middleware guaranteeing Snapshot Isolation without modification of Database Serversに基づいています。 このモードを有効にするにはbackend_clustering_modeに'snapshot_isolation'を設定してください。

backend_clustering_mode = 'snapshot_isolation'
    

たとえば、以下のようなノードにまたがる可視性の一貫性がないことからくるノード間のデータ不整合を防ぐことができます。 ここで、S1, S2はセッションを表し、N1, N2はPostgreSQLのサーバ1と2を表します。

S1/N1: BEGIN;
S1/N2: BEGIN;
S1/N1: UPDATE t1 SET i = i + 1;	-- i = 1
S1/N2: UPDATE t1 SET i = i + 1; -- i = 1
S1/N1: COMMIT;
S2/N1: BEGIN;
S2/N2: BEGIN;
S2/N2: DELETE FROM t1 WHERE i = 1; -- delete 1 row since S1/N2 is not committed yet
S2/N1: DELETE FROM t1 WHERE i = 1; -- delete no row since S1/N1 is committed and i is not 1 anymore
S1/N2: COMMIT;
S2/N1: COMMIT;
S2/N2: COMMIT;
   

スナップショットアイソレーションモードでは、以下のどちらかとなり、いずれにしてもノード間のデータの一貫性は損なわれません。

S1/N1: BEGIN;
S1/N2: BEGIN;
S1/N1: UPDATE t1 SET i = i + 1;	-- i = 1
S1/N2: UPDATE t1 SET i = i + 1; -- i = 1
S2/N1: BEGIN;
S2/N2: BEGIN;
S1/N1: COMMIT;
S1/N2: COMMIT;
S2/N1: DELETE FROM t1 WHERE i = 1; -- delete no row since S1/N1 is committed and i is not 1 anymore
S2/N2: DELETE FROM t1 WHERE i = 1; -- delete no row since S1/N2 is committed and i is not 1 anymore
S2/N1: COMMIT;
S2/N2: COMMIT;
   

S1/N1: BEGIN;
S1/N2: BEGIN;
S1/N1: UPDATE t1 SET i = i + 1;	-- i = 1
S1/N2: UPDATE t1 SET i = i + 1; -- i = 1
S2/N1: BEGIN;
S2/N2: BEGIN;
S2/N1: DELETE FROM t1 WHERE i = 1; -- delete 1 row since S1/N1 is not committed yet
S2/N2: DELETE FROM t1 WHERE i = 1; -- delete 1 row since S1/N2 is not committed yet
S1/N1: COMMIT;
S1/N2: COMMIT;
S2/N1: COMMIT;
S2/N2: COMMIT;
   

5.3.4. ロジカルレプリケーションモード

このモードではPostgreSQLが個々のサーバをレプリケーションします。 このモードを有効にするにはbackend_clustering_modeに'logical_replication'を設定してください。

backend_clustering_mode = 'logical_replication'
    

このモードでは127台までのロジカルレプリケーションサーバを使用できます。 また、スタンバイサーバをまったく使用しないことも可能です。

このモードの難点は、検索問い合わせを負荷分散させた時に、スタンバイサーバのレプリケーション遅延を意識しなければならない点です。 ノードをまたがる可視性の一貫性も保証されません。 また、DDLやラージオブジェクトなど、一部のデータオブジェクトはレプリケーションされません。

5.3.5. Slonyモード

このモードではPgpool-IISlony-Iと組み合わせて使用します。 Slony-Iが実際にデータのレプリケーションを行います。 このモードを有効にするにはbackend_clustering_modeに'slony'を設定してください。

backend_clustering_mode = 'slony'
    

このモードでは127台までのレプリカサーバを使用できます。 また、レプリカサーバをまったく使用しないことも可能です。

このモードの難点は、検索問い合わせを負荷分散させた時に、スタンバイサーバのレプリケーション遅延を意識しなければならない点です。 ノードをまたがる可視性の一貫性も保証されません。 また、DDLやラージオブジェクトなど、一部のデータオブジェクトはレプリケーションされません。

ストリーミングレプリケーションやロジカルレプリケーションが登場後、Slony-Iを新規に採用するシステムは少ないので、特に理由がない限りこのモードを使用することはお勧めしません。

5.3.6. rawモード

このモードでは、Pgpool-IIはデータベースの同期に関しては関与しません。 システム全体に意味の有る動作をさせるのはユーザの責任となります。 このモードでは負荷分散はできません。 このモードを有効にするにはbackend_clustering_modeに'raw'を設定してください。

backend_clustering_mode = 'raw'