制限事項

この章では、Pgpool-IIの現在の制限事項について説明します。

pg_terminate_backendの利用

pg_terminate_backend()を使ってバックエンドを停止すると、フェイルオーバが起こります。 これは、PostgreSQLが、postmasterの停止と全く同じメッセージをバックエンド停止時に送るためです。 Pgpool-II 3.6より前のバージョンには回避策はありません。 3.6以降では、この制限は緩和されています。 その関数の引数(プロセスIDです)が定数なら、その関数を使っても安全です。 しかし、拡張プロトコルでは、その関数は使えません。 4.3以降では、failover_on_backend_shutdownoffにすることで、pg_terminate_backend()によるフェイルオーバを完全に回避できますが、その代わりpostmasterの停止によるフェイルオーバも起きなくなります。

Load Balancing

マルチステートメントSQL(1行の中に複数のSQLが含まれている)は、常にプライマリノード(ストリーミングレプリケーションモードの場合)かマスターノード(それ以外のモード)に送られます。 通常Pgpool-IIはクエリの種類を見て適切なノードにクエリを送りますが、マルチステートメントSQLではこれが適用されません。

認証/アクセス制御

レプリケーションモードまたマスタ/スレーブモード時にはtrust、reject、pam認証方式が利用できます。 Pgpool-II 3.0以降では、pool_passwdというファイルを使ってmd5認証も使えます。 Pgpool-II 4.0以降では、scram-sha-256、cert、clear text password認証も使えます。 pool_passwdはデフォルトの認証ファイル名です。 md5認証を有効にする手順を示します。

  1. DBユーザのOSアカウントでログインし、以下を実行します。

    	 pg_md5 --md5auth --username=your_username your_passwd
    	

    ユーザ名とmd5により暗号化されたパスワードがpool_passwdに登録されます。 pool_passwdがまだ存在しなければ、pg_md5コマンドは、自動的にpgpool.confと同じディレクトリ内にpool_passwdを作成します。 pool_passwdのフォーマットは、username:encrypted_passwdです。

  2. また、pool_hba.confに適当なmd5のエントリを作成する必要があります。 詳細は項6.1を見てください。

  3. pool_passwdに登録するパスワードは、PostgreSQLに登録したパスワードと完全に同じでなければなりません。

  4. md5パスワード(もちろんpool_passwdとPostgreSQLの両方)を変更したら、pgpool reload を実行してください。

ラージオブジェクト

ストリーミングレプリケーションモードでは、Pgpool-IIはラージオブジェクトをサポートしています。

ネィティブレプリケーションモードでは、PostgreSQL 8.1以降ならばラージオブジェクトをサポートします。 その際には、pgpool.confのlobj_lock_tableを有効にしてください。 なお、バックエンド関数のlo_importを使ったラージオブジェクトのレプリケーションはサポートされていません。

Slonyモードも含め、その他のモードではラージオブジェクトはサポートされていません。

一時テーブル

一時テーブルの作成、挿入、更新、削除は、常にマスター(プライマリ)で実行されます。 テーブルに対するSELECTもマスター上で実行されます。 しかし、一時テーブル名が文字列としてSELECTで使われると、それを検知する方法がないため、SELECTは負荷分散されます。 これにより、「テーブルが見つからない」エラーになったり、同じ名前を持つ別のテーブルを検索することになります。 この問題を回避するには、SQLコメントを使ってください。

ちなみに、psqlの\dコマンドのように、システムカタログを問い合わせる中で 文字列としてのテーブル名を使っている場合:

       SELECT 't1'::regclass::oid;
      

pgpool-II 3.0以降ではマスタで検索が行なわれるので、問題になりません。 なぜなら、システムカタログへの検索は常にマスタで行なわれるからです。

PostgreSQL 8.3以後を使っているのであれば、CREATE TEMP TABLEによって作成されたテーブルは、reset_query_list中のDISCARD ALLを指定することによってセッションの最後で削除されます。

8.2.x以前では、CREATE TEMP TABLEによって作成されたテーブルは、セッションを終了した後に削除されません。 PostgreSQLバックエンドから見ると、コネクションプールによってセッションが維持されているからです。 これを回避するには、明示的にDROP TABLEを発行するか、トランザクションブロックの内側でCREATE TEMP TABLE ... ON COMMIT DROPを実施します。

ネィティブレプリケーションモードにおける関数などの扱い

文脈依存の仕組み(たとえば乱数やトランザクションID、OID、SERIAL、シーケンス)を使って提供されるデータが複数のバックエンドに正しくレプリケーションされる保証はありません。 SERIALに対しては、insert_lockを使って対応できます。 SELECT setval()とSELECT nextval()に対してもinsert_lockで対応できます。

CURRENT_TIMESTAMPCURRENT_DATEnow()を含むINSERT/UPDATEは正しくレプリケーションされます。 CURRENT_TIMESTAMPCURRENT_DATEnow()をデフォルト値として使うINSERT/UPDATEも正しくレプリケーションされます。 これは、関数を、クエリ実行時にマスターから取得した定数に置き換えることで達成されています。 しかし、いくつか制限事項があります。

Pgpool-II 3.0以前では、テーブルのデフォルト値としての時制データが正しく計算されない場合があります。 例として以下のテーブル定義を示します。

       CREATE TABLE rel1(
       d1 date DEFAULT CURRENT_DATE + 1
       )
      

これは次と同じに扱われます。

       CREATE TABLE rel1(
       d1 date DEFAULT CURRENT_DATE
       )
      

Pgpool-II 3.1以降はこのケースを正しく扱います。 ですのでd1列はtomorrowがデフォルト値になります。 しかし、この改善は拡張プロトコル(たとえばJDBC、PHP PDO)やPREPAREが使用されている場合には適用されません。

列の型が時制ではない場合は書き換えは行われないことに注意してください。 そのような例を示します。

       foo bigint default (date_part('epoch'::text,('now'::text)::timestamp(3) with time zone) * (1000)::double precision)
      

以下のテーブルがあるとします。

       CREATE TABLE rel1(
       c1 int,
       c2 timestamp default now()
       )
      

       INSERT INTO rel1(c1) VALUES(1)
      

これは以下に書き換えられるものの、

       INSERT INTO rel1(c1, c2) VALUES(1, '2009-01-01 23:59:59.123456+09')
      

       INSERT INTO rel1(c1) SELECT 1
      

は変換されません。 ですので現在の実装では正しくレプリケーションされません。 値は挿入されますが、全く変換が行われません。

SQL型コマンド

SQL型コマンドは、拡張クエリモードでは使用できません。

マルチバイト文字

現在の実装では、クライアントとPostgreSQLの間でマルチバイト文字の変換処理を行いません。 クライアントエンコーディング、バックエンドノードのサーバエンコーディングを一致させるようにしてください。

マルチステートメント

マルチステートメント(';'で区切って複数の文をまとめたSQL)をPgpool-IIが正しく処理することができません。 必ず文を分けて送信してください。 なお、psqlを使ってPgpool-IIに接続した場合は、psql内部でマルチステートメントを分解し、1つずつ送信するので、実際には問題になりません。

libpq

pgpool-II では libpq をリンクします。 libpq のバージョンが 2.0 の場合、configureに失敗します。 必ず libpq 3.0 以降(PostgreSQL 7.4以降)をリンクするようにしてください。

ParameterStatus

クライアントがPostgreSQLに接続すると、PostgreSQLは複数のパラメータ/値のペアをクライアントに返します。 このプロトコルはParameterStatusと呼ばれます。 このパラメータ/値ペアはある種のAPI、たとえばlibpqのPQParameterStatusで取得できます。 該当する実際のパラメータ名はここにあります。 Pgpool-IIはParameterStatusの値を複数のPostgreSQLサーバから収集するため、その値がサーバによって異なる可能性があります。典型的な例は、PostgreSQL 14で導入されたin_hot_standbyです。 この値はプライマリサーバではoffで、スタンバイサーバではonになります。 問題は、Pgpool-IIはその値のひとつだけをクライアントに返さなければならないことです。 この場合は、プライマリサーバの値が選択されます。 ですから、PQParameterStatusoffを返すでしょう。 一方で、クライアントがshow in_hot_standbyを発行すると、その時のセッションのロードバランスノードによって、onあるいはoffが返ります。

その値がin_hot_standby以外で異なる時には、Pgpool-IIはログメッセージを出力することに注意してください。 これは、in_hot_standbyの値は常に異なるからです。

set_config

PostgreSQLにはset_configという関数があり、SETコマンドで現在のセッションに対してパラメータの値を変更するのと同じ効果を与えることができます(実際にはSETにない機能もあります。詳細はPostgreSQLのマニュアルを見てください)。 Pgpool-IIでは、現在のクラスタリングモードstreaming_replicationの場合、プライマリサーバにのみこの関数を送信します。 スタンバイサーバにはこの関数が送信されないので、それぞれのサーバでパラメータの値が異なることになります。 この問題を回避するには、set_configの代わりにSETコマンドを使用してください。 SETコマンドは、現在のセッションが使用しているすべてのサーバに送信されるので、この問題は起きません。 ただしPostgreSQLサーバを3台以上使っているときは、statement_level_load_balanceをoffにした上でSETコマンドを使用してください。 statement_level_load_balanceがonの場合、現在のセッションが使用しているプライマリサーバ、ロードバランスノードになっているスタンバイサーバに加え、3台目のスタンバイサーバにもクエリを送信する可能性があるからです。

どうしてもset_configを使わなければならないのであれば、そのセッションでの負荷分散機能をoffにしてください(set_configだけでなく、そのセッションで負荷分散機能を使わないようにする必要があります)。 性能は犠牲になりますが、問題は回避できます。