Pgpool-II 4.1 新機能: ステートメントレベルの負荷分散【第2回】

前回の記事Pgpool-II 4.1の紹介【第1回】では Pgpool-II 4.1 の新機能について全体的に紹介しました。今回は、その中のステートメントレベルの負荷分散 機能について詳しく紹介します。

負荷分散

Pgpool-II にはクエリ負荷分散という機能があります。
データがレプリケーションされている複数台の PostgreSQL サーバクラスタでは、Pgpool-II は SELECT のような参照クエリをいずれかの PostgreSQL サーバに振り分け、検索性能を向上させることができます。参照クエリの負荷分散により、クラスタをスケールアウトすることが可能です。

セッションレベルの負荷分散

Pgpool-II 4.0 までは、振り分け先のノードがセッション開始時に決められ、セッション終了まで変更されませんでした。これはセッションレベルの負荷分散と言います。
ここでは、PostgreSQL サーバ 2 台のクラスタを例としてセッションレベルの負荷分散について紹介します。それぞれの PostgreSQL サーバにおいて、同じ比率で負荷分散するように、パラメータ backend_weight を同値に設定します。

負荷分散

上記の例では、クライアントが Pgpool-II に接続し、スタンバイサーバが振り分け先のノードとして選出されたので、更新クエリがプライマリサーバへ、参照クエリがスタンバイサーバへ振り分けられ、このセッションが終了するまで、参照クエリの振り分け先が変わりません。

ステートメントレベルの負荷分散

クライアントがその都度接続し、クエリを発行し、処理終了後に切断するようなアプリケーションの場合は、セッションレベルでも適切に負荷分散を行うことは可能ですが、クライアントでコネクションプールを利用し、Pgpool-II に接続したままのようなアプリケーションの場合は、振り分け先のノードの選出は接続時に1回しか行われないので、負荷をすべてのサーバリソースに均等に振り分けることはできない可能性があります。

その問題を解決するために、Pgpool-II 4.1 では、ステートメントレベルの負荷分散機能が追加されました。ステートメントレベルの負荷分散はセッションレベルの負荷分散とは異なり、振り分け先のノードはセッションの開始時ではなく、新しいクエリが発行されたときに決定されます。そのため、Pgpool-II への接続を保持しっぱなしのようなアプリケーションでも、クエリごとに振り分け先のノードを決めることができ、サーバリソースをより効率的に利用することが可能です。

デフォルトでは、セッションレベルの負荷分散となるので、ステートメントレベルの負荷分散機能を利用したい場合は、pgpool.conf の statement_level_load_balance というパラメータを on にする必要があります。

statement_level_load_balance = on

ステートメントレベルの負荷分散は具体的にどのように動作するかを以下の例で説明します。

まず、接続した直後は show pool_nodes の結果の select_cnt 列は 0 です。これは、両ノードに SELECT が振り分けられていないことを示します。

test=# show pool_nodes;
 node_id | hostname | port  | status | lb_weight |  role   | select_cnt | load_balance_node | replication_delay | replication_state | replication_sync_state | last_status_change  
---------+----------+-------+--------+-----------+---------+------------+-------------------+-------------------+-------------------+------------------------+---------------------
 0       | /tmp     | 11002 | up     | 0.500000  | primary | 0          | true              | 0                 |                   |                        | 2019-11-20 17:31:05
 1       | /tmp     | 11003 | up     | 0.500000  | standby | 0          | false             | 0                 | streaming         | async                  | 2019-11-20 17:31:05

次に、SELECTを実行してみましょう。

test=# SELECT 1;
 ?column? 
----------
        1

すると、ノード 1 の select_cnt が 1 になりました。これは、SELECT がノード 1 に送信されたことを示します。また、ノード 1 の load_balance_node 列は true であり、これは直前のクエリでノード 1 が振り分け先のノードとして選択されたことを示します。

test=# show pool_nodes;
 node_id | hostname | port  | status | lb_weight |  role   | select_cnt | load_balance_node | replication_delay | replication_state | replication_sync_state | last_status_change  
---------+----------+-------+--------+-----------+---------+------------+-------------------+-------------------+-------------------+------------------------+---------------------
 0       | /tmp     | 11002 | up     | 0.500000  | primary | 0          | false             | 0                 |                   |                        | 2019-11-20 17:31:05
 1       | /tmp     | 11003 | up     | 0.500000  | standby | 1          | true              | 0                 | streaming         | async                  | 2019-11-20 17:31:05

次に、別の SELECT を実行してみましょう。

test=# SELECT 2;
 ?column? 
----------
        2

2つ目の SELECT を実行すると、load_balance_node がノード 0 に変更され、ノード 0 の select_cnt が 0 から 1 になりました。なお、振り分け先のノードはランダムに選ばれるため、必ずしも node 0 -> node 1 -> node 0 … という順番になるとは限りません。

test=# show pool_nodes;
 node_id | hostname | port  | status | lb_weight |  role   | select_cnt | load_balance_node | replication_delay | replication_state | replication_sync_state | last_status_change  
---------+----------+-------+--------+-----------+---------+------------+-------------------+-------------------+-------------------+------------------------+---------------------
 0       | /tmp     | 11002 | up     | 0.500000  | primary | 1          | true              | 0                 |                   |                        | 2019-11-20 17:31:05
 1       | /tmp     | 11003 | up     | 0.500000  | standby | 1          | false             | 0                 | streaming         | async                  | 2019-11-20 17:31:05

これがステートメントレベルの負荷分散の動作となります。

おわりに

今回は、Pgpool-II 4.1 で追加されたステートメントレベルの負荷分散機能について紹介しました。この機能により、アプリケーションの接続方式に合わせて負荷分散の動作を変更することができ、サーバリソースをより効率的に利用可能になります。