PostgresForest 5.1 管理者ガイド

目次

1   本ドキュメントについて

本ドキュメントは、PostgresForestデータベース環境のインストール、セット アップおよび運用管理を行うデータベース管理者(DBA) を対象としています。

本ドキュメントでは、読者がLinux・PostgreSQLの管理に関する一般的な知識 を持っていることを前提としています。そのため、Linux・PostgreSQLに関連 する詳細な解説は省いている場合があります。

PostgreSQLについての技術情報は、 PostgreSQLオフィシャルマニュアル (http://www.postgresql.jp/document/) 等を参照してください。

2   PostgresForestの概要

PostgresForestは、PostgreSQLの可用性を向上させるためのオープンソースの ミドルウェアです。

2.1   特徴

PostgresForestは、次のような特徴を備えています。

高可用性:PostgresForestは、データベースを2台のサーバ上に冗長化して配置します。 障害発生時には、該当サーバを自動的に切り離すことでサービスをシステム の障害から分離し、高い可用性を実現します。
負荷分散:PostgresForestでは、データベースへの問い合わせ処理を2台のサーバで 振り分けることで、負荷分散を実現します。
オンラインリカバリ:障害発生後の縮退運転状態から、サービスを停止せずに正常状態に復旧させる ことができます。

2.2   構成要素

PostgresForestのデータベースシステムは、以下の要素から構成されます。

2.2.1   PostgresForestクラスタ環境

PostgresForestJDBCドライバがアクセスして、実際にデータを格納するのが PostgresForestクラスタ環境で、2台のPostgreSQLサーバで構成されます。 この2台のPostgreSQLサーバは、それぞれが以下に示す2つのデータベース を持っています。また2台のPostgreSQLサーバは、PostgresForestJDBCドラ イバの動作によって、常にレプリケーションされています。

ユーザデータベース:PostgresForestを利用しているJavaアプリケーションが、実際に使用する データを格納するためのデータベースです。Javaアプリケーションが PostgresForestJDBCドライバで更新処理を行う場合、両方のPostgreSQL サーバのユーザデータベースに同一の更新を行うことで、常にユーザデータ ベースの内容をレプリケーションしています。
管理データベース:PostgresForestJDBCドライバが動作するために必要なユーザデータベースの 整合性に関する情報や、設定情報など、各種メタデータを格納している データベースです。

2.2.2   PostgresForest-BackendUtility

PostgresForestクラスタ環境を運用する上で必要になるツール類です。この中 には、

  • 管理情報作成用スクリプト
  • PostgreSQL用ロック待ちタイムアウトパッチ
  • オンラインリカバリツール

が含まれています。

2.2.3   PostgresForestJDBCドライバ

JDBC準拠のAPIを提供するライブラリ(JARファイル)として提供されている、 PostgresForest本体となるJDBCドライバです。このJDBCドライバは、上述した クラスタ環境にアクセスして適切に負荷分散やアクセスコントロールを行い ます。ユーザには縮退などを意識させることなく、容易に高可用性を得ること ができます。

サポートされるAPIの一覧は、API一覧のドキュメントを参照してください。

3   PostgresForestクラスタ環境のセットアップ

PostgresForestJDBCドライバがアクセスするクラスタ環境を作成します。 PostgresForestクラスタ環境は、2つのPostgreSQLサーバを必要とします。 以降(本章内)の作業手順は、特に断りがない限りPostgresForestクラスタを 構成する双方のサーバ上で実施してください。

3.1   必要なソフトウェアおよび動作環境

PostgresForestクラスタは以下のような環境・ソフトウェア構成での動作確認 を行っています。

OS:RedHat Enterprise Linux 5
PostgreSQL:PostgreSQL 8.3.1
PostgresForest-BackendUtility:
 postgresforest510beutil.tar.gz

PostgresForest-BackendUtilityに含まれるロック待ちタイムアウトパッチを 使用する場合、PostgreSQLはソースコードからのコンパイルする必要あります。

3.2   PostgreSQLソースへのパッチ適用・コンパイル

PostgresForest-BackendUtilityに含まれるロック待ちタイムアウトパッチは、 PostgresForest特有の「ノード間デッドロック」を解消するための仕組みを PostgreSQLに追加するパッチです。このパッチを適用しない場合、アプリケー ション開発者はノード間デッドロックで停止する可能性のあるすべてのSQLに 「NOWAIT」句を付加し、ロック待ちが起きないよう考慮が必要になります。

PostgresForest-BackendUtilityに含まれるロック待ちタイムアウトパッチを 適用した上で、PostgreSQLをソースコードからコンパイルします。

例:

(/home/forest以下にPostgreSQLのソースtarballと、PostgresForest-BackendUtilityを置いた前提です)
$ tar zxvf postgresql-8.3.1.tar.gz
$ tar zxvf postgresforest510beutil.tar.gz
$ patch -p1 -d ./postgresql-8.3.1 < postgresforest510beutil/patch/pg831-locktimeout.patch
$ cd postgresql-8.3.1
$ ./configure --prefix=/home/forest/pg831-lt
$ make
$ make install

これにより、 /home/forest/pg831-lt 以下に、ロック待ちタイムアウト パッチを適用したPostgreSQLのバイナリ類が配置されます。

3.2.1   ノード間デッドロックとは

ユーザアプリケーションから更新SQLなどが実行された場合、PostgresForest JDBCは、PostgresForestクラスタを構成する2つのPostgreSQLサーバに、順序 性無くSQLを発行します。そのため、次のような問題が発生する場合があります。

App1とApp2の2つのアプリケーションが、ほぼ同時に「lock tableA」という SQLを発行したとします。確率的にですが、次のような動作順序になる可能性 があります

1. App1 が PostgreSQLサーバ1 のtableAのロックを取得
2. App2 が PostgreSQLサーバ2 のtableAのロックを取得
3. App1 が PostgreSQLサーバ2 のtableAのロックを取得待ち(App2が取得したロックの解放待ち)
4. App2 が PostgreSQLサーバ1 のtableAのロックを取得待ち(App1が取得したロックの解放待ち)

この場合、App1、App2共に、それ以降処理が進まなくなります。また、双方の PostgreSQLサーバにとって単純なロック待ちであり、デッドロックとは認識 されません。そのため、PostgreSQLの持つデッドロックの機構が働かず、2つ のアプリケーションは永久に互いのロック取得を待ち続けることになります。

PostgresForestで提供しているロック待ちタイムアウトパッチは、「長時間 ロック取得ができずに待つ状態」を異常状態とみなし、強制的にロックを解除 したうえで、エラーを返却するようにします。

3.3   PostgreSQLデータベース領域の作成・設定

実行例:

~/pg831-lt/bin/initdb -D ~/forestdata --no-locale -E UTF8

これにより、 /home/forest/forestdata に、PostgresForestクラスタを 構成するそれぞれのPostgreSQLのデータディレクトリが作成されます。

initdbコマンドの詳細については、PostgreSQLドキュメントを参照してください

以降、PostgreSQLデータディレクトリ内の設定ファイルを、PostgresForest クラスタ環境として使用するための編集を行います。

3.3.1   待ち受けポート設定

PostgresForestJDBCは、PostgresForestクラスタ環境とTCPソケットにて通信を 行います。そのため、PostgreSQLに対してJDBCドライバを動作させるサーバから TCPソケットで通信できるように設定する必要があります。

postgresql.conf の listen_address のパラメータで、PostgreSQLが待ち 受けを行うインターフェースを指定します。

例:

listen_addresses = '*'

上記の例では全てのインターフェースで待ち受けを可能にします。

postgresql.conf の詳細については、PostgreSQLドキュメントを参照して ください。

3.3.2   アクセスコントロール設定

pg_hba.conf でホストのアクセス制御の設定をおこないます。以下の ユーザデータベースの作成管理情報データベースの作成 で作成する データベースに、アクセス可能な設定とする必要があります。

例:

host    all         all         192.168.1.0/24      trust

上記の設定を行うと、「192.168.1.0/24」ネットワークからPostgreSQLサーバ へのアクセスを、無条件で許可することができるようになります。

postgresql.conf の詳細については、PostgreSQLドキュメントを参照して ください。

3.3.3   ロック待ちタイムアウトの設定

PostgresForest-BackendUtilityに含まれるロック待ちタイムアウトパッチを PostgreSQLに対して適用した場合、何秒間ロック待ちをした場合にエラーと するかを設定する必要があります。

postgresql.conf に、独自パラメータを追加します。

設定例:

lock_timeout = 30s

上記設定により、PostgreSQL内部でロックが取得できない場合に、ロックを取得 できるまで待つ時間を30秒間だけ許容し、それを経過するとエラーを返却する ようになります。

この設定値はクラスタを構成する各系で異なる値とすることを推奨します。 ロック待ちとなっている片方のトランザクションがエラーとなり、 もう一方のトランザクションはロック待ちから解放されて処理が継続されます。

3.3.4   リカバリツール用設定

オンラインリカバリツールを使用する場合、次の設定をすべて施している必要 があります。

PostgreSQLをアーカイブモードで動作させるように、 postgresql.conf の 下記の設定を変更します。

archive_mode = on

アーカイブモードをONとした場合、アーカイブコマンドを設定する必要があり ます。平常時(リカバリ実行時以外)にアーカイブログを取得する必要がなけ れば、「true」コマンド(常に0を返却するLinuxコマンド)を設定しておけば アーカイブログのローテーションなどを考慮する必要がなくなります。

archive_command = 'true'

PostgreSQLのアーカイブログを取得するような運用設計となっている場合、 この設定変更は必要ありません。(その場合はリカバリコマンド使用時のコン フィグレーションを変更する必要があります)

アーカイブログを保存するためのディレクトリを、PostgresForestクラスタの データベースディレクトリ以下に作成します。

$ mkdir ~/forestdata/pg_archive

3.4   ユーザデータベースの作成

実際にアプリケーションが必要とするデータベースを作成します。PostgreSQL を起動した上で、通常のPostgreSQLと全く同様の方法でデータベースを作成し ます。下記の例では「userdb」という名前のデータベースを作成しています。

例:

$ ~/pg831-lt/bin/pg_ctl -w -D ~/forestdata start
$ ~/pg831-lt/bin/psql -d template1
template1=# CREATE DATABASE userdb;

pg_ctl、psql、CREATE DATABASE 等の詳細については、PostgreSQLドキュメント を参照してください

3.5   管理情報データベースの作成

管理情報データベースは、ユーザデータベースが存在する2つのPostgreSQL サーバにて、ユーザデータベースと1対1で作成しなければなりません。 ユーザデータベースの作成 で作成したデータベースに対応した管理情報 データベースを作成します。

管理情報データベースの作成には、PostgresForest-BackendUtilityに含まれる createmngdb.sh を使用します。

書式:

createmngdb.sh [PSQL-COMMAND] [IP] [PORT] [USERNAME] [IP0:PORT0] [IP1:PORT1] [USERDB]

オプション:

PSQL-COMMAND: PostgreSQLへの接続に使用するPSQLコマンドのパス
IP:           管理情報データベースを作るPostgreSQLサーバのIP
PORT:         管理情報データベースを作るPostgreSQLサーバのポート番号
USERNAME:     管理情報データベースを作る際のPostgreSQLユーザ
IP0:PORT0:    serverid=0として登録するPostgreSQLインスタンスのIPとポート番号
IP1:PORT1:    serverid=1として登録するPostgreSQLインスタンスのIPとポート番号
USERDB:       管理対象データベースを作る対象のユーザデータベース名

例:

./createmngdb.sh ~/pg831-lt/bin/psql 192.168.1.100 5432 forest 192.168.1.100:5432 192.168.1.101:5432 userdb

上記の例のコマンドを実行することで、以下の処理が実行されます。

  1. 第1引数のpsqlコマンドを使用して、第2引数と第3引数で指定された PostgreSQLに、第4引数のユーザ名で接続します
  2. 接続したPostgreSQLに userdb_pghainfo という名前の管理情報データ ベースを作成します。(第7引数の userdb_pghainfo という 文字列を付けたものが管理情報データベース名になります)
  3. userdb_pghainfo (管理情報データベース)中に、管理情報を格納する 各種テーブルを作成します
  4. 管理情報データベース中の各種設定テーブルにはデフォルトの設定値を挿入 します
  5. 管理情報データベース中の接続先情報テーブルには、serverid=0 として 第5引数の 192.168.1.100:5432 を、serverid=1 として第6引数の 192.168.1.101:5432 を登録します

注:どちらのPostgreSQLサーバに対して実行する場合も、 IP0:PORT0 と IP1:PORT1 の順を同じにしなくてはなりません。逆にした場合、PostgresForest JDBCドライバが正常に動作しません。

3.6   テーブル・データの用意

3.6.1   PostgresForestJDBCが動作していない場合

データ移行時やメンテナンス時などで、PostgresForestJDBCドライバを使用する アプリケーションが動作していない場合、 psql などのPostgreSQL標準の ユーティリティを使用して、テーブル・データの作成・更新を行うことができ ます。但しこの場合、必ず双方のPostgreSQLサーバに対して同様の操作を行い、 全てのデータを同一にする必要があります。

3.6.2   PostgresForestJDBCが動作している場合

PostgresForestJDBCドライバが1つでも動作している場合、 psql などの PostgreSQLのコマンドでユーザデータベースに対して更新を行うことはできま せん。

PostgresForestJDBCドライバを使用したサービス(アプリケーション)が動作 している中でデータを操作(バッチ処理等)をしたい場合、それらもPostgres ForestJDBCドライバを使用したアプリケーションとして作る必要があります。

4   PostgresForestJDBCドライバ動作環境のセットアップ

前節で準備したPostgresForestクラスタ環境にアクセスする、PostgresForest JDBCドライバを使ったアプリケーションを用意します。

4.1   必要なソフトウェアおよび動作環境

PostgresForestJDBCドライバを使用したアプリケーションは、以下の環境での 動作を確認しております。

PostgresForestJDBC動作環境
OS:RedHat Enterprise Linux 5
Java:Sun JRE 5.0 Update 22
PostgreSQL JDBC Driver:
 postgresql-8.4-701.jdbc3.jar
PostgresForestJDBC:
 postgresforest510.jar

4.2   アプリケーションの作成

PostgresForestJDBCドライバを使用したアプリケーションの作成については、 開発者ガイドを参照してください。

4.3   アプリケーションを起動する

PostgresForestJDBCドライバを使用したアプリケーションやサービスを動作 させる場合、動作を開始する段階で双方のPostgreSQL上のユーザデータベース のデータが、同じになっている必要があります。

PostgresForestJDBCドライバは、JDBCドライバ動作開始時の各PostgreSQLサーバ 上のユーザデータベースの内容が完全に一致していることを前提に動作をします。

5   PostgresForestクラスタ環境の監視

PostgresForestJDBCドライバは、何らかの問題によりPostgresForestクラスタ のどちらかのユーザデータベースを縮退状態とした場合でも、特にアプリケー ションで異常を検知することはありません。

そのため、データベース管理者は定期的にPostgresForestクラスタ環境を監視 し、縮退などが発生していないか確認をし、異常状態となっていれば、その 復旧を行う必要があります。

5.1   データベースのステータス

PostgresForestデータベース環境において、各PostgreSQLサーバ上のユーザ データベースの状態には、以下の3つの状態があります。

5.1.1   正常状態

このPostgreSQLサーバ上のユーザデータベースに対して、問題なく更新が 行われており、整合性が取れている状態です。管理情報データベース中の server_info テーブルの udb_validity の値が 1 となっている 場合が該当する状態です。

5.1.2   不整合発生状態

このPostgreSQLサーバ上のユーザデータベースは異常があると判断されて います。そのため、PostgresForestJDBCはこのPostgreaSQLサーバ上のユーザ データベースをアクセスする対象とはしていない状態です。管理情報データ ベース中の server_info テーブルの udb_validity の値が -1 となっている場合が該当する状態です。

5.1.3   処理抑制状態

オンラインリカバリツールを動作させている際に発生する状態です。正常状態 のPostgreSQLサーバからデータを取得し、不整合発生状態のPostgreSQLサーバ にそのデータを適用している際に、アプリケーションがトランザクションを 開始するのを一時的に停止させていることを意味する状態です。管理情報 データベース中の server_info テーブルの udb_validity の値が 0 となっている場合が該当する状態です。(これはオンラインリカバリ 中のみのステータスです)

PostgresForestクラスタ環境では、ユーザデータベースへのアクセス中に、双方 のPostgreSQL間で整合性が崩れる問題が発生すると、問題が発生したPostgreSQL サーバ上にあるユーザデータベースへのアクセスを自動的に停止します。

「不整合発生状態」となった場合には、すみやかに何らかの対応を行わなくて はなりません。そのため、PostgresForestクラスタ環境を監視している必要が あります。

5.2   ステータスを管理情報データベースから取得する

各PostgreSQLサーバ上のユーザデータベースは、整合性が取れているのか否か を調べるには、psqlなどで双方の管理情報データベースの情報を取得する必要 があります。

取得例1:

$ psql -h 192.168.1.100 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |            1
        1 | 192.168.1.101:5432/userdb |            1
(2 rows)

$ psql -h 192.168.1.101 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |            1
        1 | 192.168.1.101:5432/userdb |            1
(2 rows)

双方の管理情報中で、双方サーバとも正常状態(udb_validity = 1)と認識 されているため、縮退は発生していません。

取得例2:

$ psql -h 192.168.1.100 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |            1
        1 | 192.168.1.101:5432/userdb |           -1
(2 rows)

$ psql -h 192.168.1.101 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |            1
        1 | 192.168.1.101:5432/userdb |           -1
(2 rows)

双方の管理情報中で、serverid=1 側のユーザデータベースが不整合発生状態 (udb_validity = -1)と認識されています。この状態では serverid=1 の ユーザデータベースに対してアクセスが行われない(すなわち serverid=1 側 は縮退)状態となっています。

取得例3:

$ psql -h 192.168.1.100 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |            1
        1 | 192.168.1.101:5432/userdb |            1
(2 rows)

$ psql -h 192.168.1.101 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |            1
        1 | 192.168.1.101:5432/userdb |           -1
(2 rows)

各PostgreSQLサーバごとに、管理情報中でのステータスが異なっています。 serverid=0 が持つ管理情報では serverid=1 のユーザデーターべースは正常 状態となっており、serverid=1 が持つ管理情報では serverid=1 のユーザ データベースは不整合発生状態となっています。

同一のサーバに対して、ステータスが「正常状態」と「不整合発生状態」とで 異なっている場合、「不整合発生状態」が優先されます。すなわち、この場合、 取得例2と同様に serverid=1 のユーザデータベースが不整合発生状態と認識 されることとなります。

取得例4:

$ psql -h 192.168.1.100 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |           -1
        1 | 192.168.1.101:5432/userdb |           -1
(2 rows)

$ psql -h 192.168.1.101 -p 5432 -d userdb_pghainfo -c 'select * from server_info'
 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |           -1
        1 | 192.168.1.101:5432/userdb |           -1
(2 rows)

この場合、殆ど同時刻に双方のPostgreSQLサーバで異なる問題が発生した、など の理由で双方のユーザデータベースが不整合状態となっており、完全にサービス が停止している状態です。

6   PostgresForestデータベースのバックアップ

PostgresForestクラスタのバックアップ取得は、次の2種類の方法があります。

6.1   ファイルシステムの物理バックアップ

ファイルシステムの物理バックアップは、PostgresForestクラスタを構成する PostgreSQLのデータディレクトリを直接バックアップします。この方法は、 サービス(PostgreSQL含む)を停止させる必要がありますが、複雑な処理が 必要ないことから、レストアが高速かつ容易です。

ファイルシステムの物理バックアップを取得する場合の手順は、以下のように なります。

  1. 全てのアプリケーションを停止する
  2. 双方のPostgreSQLサーバを停止する
  3. 双方のPostgreForestクラスタのデータディレクトリを何らかのコマンドを使用して 別ディレクトリ・外部ストレージ等にコピー・退避する
  4. 双方のPostgreSQLサーバを起動する
  5. アプリケーションを起動する

6.2   pg_dumpによる論理バックアップ

PostgresForestクラスタは、縮退が発生していない限り、常に2つのPostgreSQL 間でデータが同じ内容になっています。そのため、片方のPostgreSQLからのみ 論理バックアップを取得すればよいことになります。

ステータスを管理情報データベースから取得する を参照し、ユーザデータ ベースが正常状態となっているPostgreSQLを確認した上で、そのサーバから バックアップを取得します。

実行例:

$ ~/pg831-lt/bin/pg_dump -h 192.168.1.100 -p 5432 -U forest -C userdb > ~/userdb.sql
$ ~/pg831-lt/bin/pg_dump -h 192.168.1.100 -p 5432 -U forest -C userdb_pghainfo -C ~/forestinfo.sql

これによって、192.168.1.100:5432 側で動作しているPostgreSQLサーバから バックアップを取得し、userdb.sqlファイルにはユーザデータベースの内容が、 forestinfo.sqlファイルには管理情報データベースの内容が格納されます。

ラージオブジェクトや外部関数などを登録している場合、pg_dumpコマンドを 使用する際のオプションを変更する必要があります。

pg_dump コマンドの詳細については、PostgreSQLドキュメントを参照して ください。

7   PostgresForestデータベースのリストア

バックアップを取得した方法に応じて、リストアの方法が異なります。

7.1   ファイルシステムの物理バックアップからのリストア

ファイルシステムの物理バックアップからリストアする場合の手順は、以下の ようになります。

  1. 全てのアプリケーションを停止する
  2. 双方のPostgreSQLサーバを停止する
  3. 双方の既存PostgreForestクラスタのデータディレクトリを削除する
  4. バックアップから双方のPostgresForestクラスタのデータディレクトリを配置する
  5. 双方のPostgreSQLサーバを起動する
  6. アプリケーションを起動する

7.2   pg_dumpによる論理バックアップからのリストア

pg_dumpによる論理バックアップ に記載したオプションでバックアップを 取得している場合に、そのバックアップからリストアする手順が以下のように なります。(異なるオプションを使用している場合には、リストア方法が異なる 場合があります)

  1. 全てのアプリケーションを停止します

  2. 双方のPostgreSQLサーバ上の、ユーザデータベースと管理情報データベースを削除します

    実行例:

    $ ~/pg831-lt/bin/dropdb -h 192.168.1.100 -p 5432 -U forest userdb
    $ ~/pg831-lt/bin/dropdb -h 192.168.1.100 -p 5432 -U forest userdb_pghainfo
    $ ~/pg831-lt/bin/dropdb -h 192.168.1.101 -p 5432 -U forest userdb
    $ ~/pg831-lt/bin/dropdb -h 192.168.1.101 -p 5432 -U forest userdb_pghainfo
    
  3. 双方のPostgreSQLサーバに、ユーザデータベースと管理情報データベースをリストアします

    実行例:

    $ ~/pg831-lt/bin/psql -h 192.168.1.100 -p 5432 -U forest template1 < ~/userdb.sql
    $ ~/pg831-lt/bin/psql -h 192.168.1.100 -p 5432 -U forest template1 < ~/forestinfo.sql
    $ ~/pg831-lt/bin/psql -h 192.168.1.101 -p 5432 -U forest template1 < ~/userdb.sql
    $ ~/pg831-lt/bin/psql -h 192.168.1.101 -p 5432 -U forest template1 < ~/forestinfo.sql
    

    この場合の template1 は、初期接続のためのデータベースです。

8   PostgresForestデータベースのリカバリ

PostgresForestクラスタ環境で縮退が発生した場合に、両系正常状態に戻す 方法としては、以下の方法があります。

片方縮退の場合

オフラインでのリカバリ
PostgresForestJDBCを使用するアプリケーションを完全に停止するなど、 PostgresForestクラスタ環境にアクセスがない状態として、不整合が発生 しているデータベースの内容を正常状態のデータベースの内容で上書き する方法です
オンラインでのリカバリ
PostgresForestJDBCを使用するアプリケーションを停止させることなく、 専用のリカバリツールを使用して、不整合が発生しているデータベースの 内容を正常状態のデータベースの内容と同期する方法です

両系縮退の場合

バックアップからのリカバリ
PostgresForestデータベースのリストア に示した方法で、バックアップ からリストアすることで、バックアップ時点の情報に完全に戻します。 PostgresForestデータベースのリストア を参照してください

8.1   オフラインでのリカバリ

オフラインでのリカバリの手順は以下のようになります。

  1. アプリケーションを停止します

  2. PostgreSQLは双方共起動状態としておく

  3. 正常状態のデータベースから論理バックアップを取得する

    pg_dumpによる論理バックアップ に記載した方法で、正常状態のユーザ データベースを持つPostgreSQLから、論理バックアップを取得します

  4. 論理バックアップを不整合発生状態のデータベース側に適用する

    不整合が発生しているユーザデータベースが存在するPostgreSQLサーバに 対して、3で取得した論理バックアップを適用します

    192.168.1.101のPostgreSQLが不整合発生状態の場合の実行例:

    $ ~/pg831-lt/bin/dropdb -h 192.168.1.101 -p 5432 -U forest userdb
    $ ~/pg831-lt/bin/dropdb -h 192.168.1.101 -p 5432 -U forest userdb_pghainfo
    $ ~/pg831-lt/bin/psql -h 192.168.1.101 -p 5432 -U forest template1 < ~/userdb.sql
    $ ~/pg831-lt/bin/psql -h 192.168.1.101 -p 5432 -U forest template1 < ~/forestinfo.sql
    
  5. ユーザデータベースのステータスを変更する

    管理情報データベースに格納されている、ユーザデータベースの整合性に ついて、双方のユーザデータベースに不整合がない状態を示すように書き 換えをします。双方のPostgreSQLサーバに対して実施します。

    $ ~/pg831-lt/bin/psql -h 192.168.1.100 -p 5432 -U forest userdb_pghainfo -c "UPDATE server_info set udb_validity = 1"
    $ ~/pg831-lt/bin/psql -h 192.168.1.101 -p 5432 -U forest userdb_pghainfo -c "UPDATE server_info set udb_validity = 1"
    
  6. アプリケーションを起動する

8.2   オンラインでのリカバリ

PostgresForest-BackendUtilityに付属のオンラインリカバリツールは、 PostgresForestJDBCを使ってアクセスするアプリケーションを停止すること なく、不整合発生状態となったPostgreSQLサーバのデータを、正常状態の PostgreSQLサーバのデータと同期させます。

8.2.1   オンラインリカバリの必須前提条件

オンラインリカバリツールは、以下のような条件を満たしている場合にのみ使用 することができます。

  • リカバリ用設定が施されている

    リカバリツール用設定 に記載されたアーカイブモードの設定をして いる必要があります。

  • 管理情報の読み込み設定が有効になっている

    管理情報読み込み間隔 に記述している、管理情報の定期更新が行われ ている必要があります。

  • 片系縮退の状態であること

    片方のPostgreSQLサーバ上のユーザデータベースのみが不整合発生状態と して認識されている場合以外は使用できません。

  • アプリケーションがオンラインリカバリに対応した作りになっていること

    開発者ガイドの「SET句などを使用した場合のオンラインリカバリの制限」 に記載したように、SET句などのコネクションの状態を変更するSQLを使用 していないアプリケーションである必要があります。

pgha_recovery.conf の設定次第で、様々な環境でのリカバリが可能です が、以下で解説する設定内容(下記手順)は、次の条件を満たしている場合に のみ有効に動作します。

  • 両系のPostgreSQLサーバが別の物理マシン上で動作している
  • 両系のPostgreSQLサーバが同一の設定で動作している (ポート番号設定やアクセスコントロールの設定などを含む)
  • 両系のPostgreSQLのバイナリ(pg_ctlなど)が同一パスに存在する
  • 両系のPostgresForestクラスタのデータディレクトリ、アーカイブログディレクトリが同一パスに存在する
  • 両系のPostgreSQLが同一のシステムユーザ名で起動されている

これ以外(例えば、双方のPostgreSQLが同一筺体内で動作している等)の場合、 下記の設定ではオンラインリカバリはできません。

8.2.2   想定リカバリ環境

server_infoテーブルが以下に定義されるような環境で、オンラインリカバリを 実施することとします

 serverid |          udb_url          | udb_validity
----------+---------------------------+--------------
        0 | 192.168.1.100:5432/userdb |            1
        1 | 192.168.1.101:5432/userdb |           -1

serverid=1 側のPostgreSQLサーバ上のユーザデータベースが、不整合発生 状態となっているため、 serverid=0 側のユーザデータベースの内容を もとにして、 serverid=1 側のユーザデータベースを復旧する、という リカバリを実施します。

8.2.3   事前設定

PostgresForest-BackendUtilityに含まれるrecoveryツールの設定ファイルを 環境に合わせて編集します。双方のPostgreSQLサーバ上で、設定ファイルの 書き換えが必要です。

デフォルトのpgha_recovery.conf:

# directory definition
pg_dir="/home/forest/pg831-lt"
dbcluster_dir="/home/forest/forestdata"
archivexlog_dir="${dbcluster_dir}/pg_archive"

# access definition
pg_user="forest"
pg_db="template1"
pg_port="5432"
src_pg_host="192.168.1.101"
dst_pg_host="192.168.1.102"

# server configuration
#  - size of archived wal file must be 16MByte
archive_command="cp %p ${archivexlog_dir}/%f"
restore_command="cp ${archivexlog_dir}/%f %p"

# timeout definition
#  - max time[sec] for transaction(s) to idle
idle_wait_timeout=20
archive_wait_timeout=10

# command for base recovery
base_recovery_command="/usr/bin/scp -24qp -r ${dbcluster_dir} ${dst_pg_host}:${dbcluster_dir%/*}"

# command for sync recovery
sync_recovery_command="/usr/bin/scp -24qp -r ${archivexlog_dir} ${dst_pg_host}:${dbcluster_dir}"

# command for startup instance at recovery node
instance_startup_command="/usr/bin/ssh -24q ${dst_pg_host} ${pg_dir}/bin/pg_ctl start -w -D ${dbcluster_dir} -l ${dbcluster_dir}/pgsql.log"

環境に合わせて、各変数値を変更します。 オンラインリカバリの必須前提条件 を全て満たしている環境で使用する 場合、以下の項目のみを編集することで動作します。

pg_dir:PostgreSQLのインストールディレクトリ
dbcluster_dir:PostgresForestクラスタデータベース領域のディレクトリ
archivexlog_dir:
 PostgresForestクラスタデータベース領域内でアーカイブログ用に作成した ディレクトリ ( リカバリツール用設定 参照)
pg_user:PostgreSQLのスーパーユーザ名
pg_port:PostgreSQLの接続ポート番号
src_pg_host:リカバリの元となるPostgreSQLサーバの接続ホスト名(IPアドレス)
dst_pg_host:もう片方のPostgreSQLサーバの接続ホスト名(IPアドレス)
idle_wait_timeout:
 オンラインリカバリツールが全てのトランザクションの終了を待つ際に、 待つ上限時間(秒) これ以上の時間、トランザクションが無くならない 場合は、リカバリツールの動作をエラーとして中断する

続いて、必要に応じてPostgreSQLのログインパスワードをファイルに記述します。 オンラインリカバリツールは、その動作中に何度もPostgreSQLに接続し、データ ベースの内容を参照・更新します。 アクセスコントロール設定 で、無条件に ログイン可能としている場合は必要ありませんが、パスワード認証などを選択 している場合、頻繁にPostgreSQLへのログインパスワードの入力を求められる ことになるため、オペレーションミスをすることでリカバリを失敗することを 防ぐためにも、用意をすることが望ましいです。

記述するファイルは .pgpass というファイル名で、OSユーザのホームディ レクトリ直下に配置します。今回の例では、 /home/forest/.pgpass に配置 します。

設定例:

$ echo '*:*:*:forest:forest_pass' > ~/.pgpass
$ chmod 600 ~/.pgpass

これにより、PostgreSQL内部ユーザ「forest」でPostgreSQLにアクセスしよう とした場合、自動的に「forest_pass」というパスワードで接続処理が行われる ことになります。

.pgpass の詳細については、PostgreSQLドキュメントを参照して ください。

また、 pgha_recovery.conf に記述した内容からもわかる通り、2つの PostgreSQLを動作させているホスト間で、SSHやSCPなどによる通信を何度も 実行することになります。そのため、その都度SSHやSCPのログインパスワード を入力する必要が出てくることから、オペレーションミスをすることで リカバリが失敗することを防ぐためにも、SSH/SCPでパスワード入力をせずに 済むよう、ログイン用鍵交換を実施しておくことが望ましいです。 (あるいはSSH/SCPなどのログインが必要な方式ではなく、rsh/rcpなどの ログインの必要がないコマンドを選択するという方法もあります)

SSHの鍵交換の方法については、本ドキュメントでは省略します。

上記のデフォルトの設定ファイルでは、 両系で全く同じ postgresql.conf ファイルにより 稼働させている場合に利用できますが、異なる postgresql.conf ファイルを 利用している場合にも対応したサンプル設定ファイルも用意しています。

pgha_recovery_scp.conf:
 scpにより通信を行うサンプル設定ファイルです。 recovery_util.shPGHARecovery.sh と同じディレクトリに配置して利用できます。
pgha_recovery_rsync.conf:
 rsyncにより通信を行うサンプル設定ファイルです。 通信帯域を指定可能であり、リカバリに要する負荷を抑えつつ実行できます。 recovery_util.shPGHARecovery.sh と同じディレクトリに配置して利用できます。

8.2.4   リカバリの実施

  1. 障害を取り除く
リカバリを開始する前に、縮退が発生した原因を取り除く必要があります。 (例えば、ディスクが溢れた状況であればディスク使用量を減らす、ネット ワークが断線したのであれば、それを修正する、等)
  1. 復旧対象のPostgreSQLを停止

復旧対象(serverid=1 側)のPostgresForestクラスタを構成するPostgreSQL が起動しているかを確認し、起動しているようであれば、停止します。

停止例:

$ ~/pg831-lt/bin/pg_ctl stop -m f -D ~/forestdata
  1. 復旧対象のPostgreSQLのデータディレクトリ削除

復旧対象(serverid=1 側)のPostgresForestクラスタを構成するPostgreSQL のデータディレクトリを削除します。(あるいは別の場所に退避するなどして データディレクトリを配置する場所に何もない状態にしておきます)

$ rm -rf ~/forestdata
  1. 復旧元でオンラインリカバリコマンドを実施する

正常状態のPostgreSQL側で、復旧のためのコマンドを実行します。 PostgresForest-BackendUtilityに含まれる、 PGHARecovery.sh コマンド を実行します。

書式:

./PGHARecovery.sh [ -all | -base | -closevm | -sync | -recovery | -openvm | -cleanup | -cancel ] [CONFIGFILE]

通常は、 -all-cleanup のみ(失敗時には -cancel )を使用し ます。各オプションの詳細については、オンラインリカバリツールのドキュ メントを参照してください。

復旧元では -all オプションを使用してリカバリを実行します。

実行例:

$ ./PGHARecovery.sh -all ./pgha_recovery.conf
----------------------------------------
online recovery (base) started
----------------------------------------
- reloading postgresql.conf for recovery...
- reloading postgresql.conf for online...
current configuration : archive_mode = on
current configuration : archive_command = true

(... 省略 ...)

[ OK ]
- removing archived WAL file(s)...
[ OK ]
----------------------------------------
online recovery (cleanup) successful
----------------------------------------

----------------------------------------
execute -cleanup for recovery node
----------------------------------------

このメッセージが出た段階で、復旧元から復旧対象へのデータの転送、JDBCの 更新抑制、データ差分是正、復旧対象へのJDBCコネクション復活、更新抑制解除 が完了しており、リカバリはほぼ完了しています。

  1. 復旧対象側でのオンラインリカバリコマンドの実施

復旧対象側で、オンラインリカバリ実施用の不要データを収集する設定になって いるためその解除を行います。

実行例:

$ ./PGHARecovery.sh -cleanup ./pgha_recovery.conf
  1. (必要あれば)パスワードファイルを削除

事前設定 で記述した .pgpass ファイルを削除します。このファイル が存在している場合、PostgreSQLに無条件にログインできることになって しまうため、リカバリの際以外は削除しておくことが必要です。

実行例:

$ rm ~/.pgpass

8.2.5   リカバリに失敗する場合

前項4.の、復旧元でオンラインリカバリコマンドを実行する、の際に、エラー が発生した場合、一旦リカバリの実施をキャンセルし、エラーが発生した原因を 排除した上で再度リカバリを実施します。

キャンセル:

$ ./PGHARecovery.sh -cancel ./pgha_recovery.conf

キャンセル後、エラーが発生する原因を取り除いた後に、再度 リカバリの実施 の 手順2より実行してください。

リカバリに関する手順のミスや設定のミス以外で、リカバリツールが実行に 失敗する原因として、リカバリ実行中のアプリケーションからのSQL実行 (トランザクション)の関係があります。リカバリツールは、アプリケーション からの新規トランザクションを抑制し、既存のトランザクションが全て処理 し終わるのを待ちます。そのため、仮に時間内にトランザクションが全て終了 しなかった場合には、リカバリの実行に失敗します。この場合も上記の方法で 再度リカバリを行ってください。

但し、開発者ガイドの「トランザクション時間によるオンラインリカバリの制限」 に書かれているように、長時間のトランザクションばかりのアプリケーション や、トランザクションをプーリングするアプリケーションの場合、オンライン リカバリツールは成功しません。

9   管理情報データベース仕様

本章では、管理情報データベース中の全テーブルについて、テーブルとカラム の概要を示します。

9.1   管理情報データベーステーブル一覧

テーブル・ビュー名 概要
server_info ユーザデータベースのアクセス先・整合性情報
global_config PostgresForestのグローバルな設定
local_config 各コネクションごとのローカル設定
broken_log broken_log_detailテーブルの一部の情報
broken_log_detail 縮退発生時のエラーやスタックトレースなどの情報

9.2   server_infoテーブル

PostgresForestクラスタの管理情報が、管理対象とするユーザデータベースに 関する情報を保持しているテーブルです。

カラム名 概要 動作中変更可否
serverid サーバID ×
udb_url ホスト名:ポート番号/ユーザデータベース名 ×
udb_validity ユーザデータベースの整合性 ×

PostgresForestJDBCドライバが動作している最中に、このテーブルの内容を ユーザが変更することは想定されておりません。変更する場合は必ず PostgresForestJDBC(を使用しているアプリケーション)を停止してください。

変更する状況としては以下が考えられます。

  • オフラインでのリカバリ後に udb_validity を変更する
  • サーバのホスト名(IP)、ポート番号が変更になり、 udb_url を変更する

変更する場合、必ず双方のPostgreSQLに存在する管理情報データベースで同一 の内容にしなくてはなりません。

9.3   global_configテーブル

PostgresForest全体で共通の動作設定値を格納したテーブルです。このテーブル の内容は、PostgresForestJDBCドライバが動作中に変更することが可能です。

(コンフィグレーション名・コンフィグレーション値の詳細は次節参照)

カラム名 概要 動作中変更可否
key コンフィグレーション名
value コンフィグレーション値

9.3.1   初期状態における設定値

keyカラムの格納値 valueカラムの格納値 デフォルト値 範囲 動作中変更可否
mngdb_read_duration 管理情報読み込み間隔[秒](0の場合再読み込みを行わない) 30 0~2147483647
mngcon_create_timeout 管理情報読み込みコネクション生成時のタイムアウト時間 10 0~2147483647
mngquery_exec_timeout 管理情報読み込みコネクションでのSQL実行タイムアウト時間 10 0~2147483647
mngdb_max_burst_error 管理情報読み込みに失敗した場合に縮退せず読み込み続ける回数 (この回数を超えて、連続した失敗が発生すると縮退します。 なお、-1と指定することで、管理情報読み込みに失敗しても縮退しない動作となります。) 2 -1~2147483647
broken_error_prefix 縮退対象とするエラーコードのプレフィックス null 任意の文字列
log_level JDBCのログ出力レベル(0 無し ~ 4 全て) 2 0~4
log_formatter_name JDBCのログ出力に使うjava.util.logging.Formatterの実装名 org.postgresforest.util.ForestLogFormatter 任意の文字列
log_console_enable JDBC動作時の標準出力へのロギング有無 1 0, 1
log_file_enable JDBC動作ホスト上でのファイルへのロギング有無 0 0, 1
log_file_name JDBC動作ホスト上での出力ファイルのフルパス(java.util.Logging.FileHandlerの命名規則に従う) /var/log/forest/forest.log.%u-%g 任意の文字列
log_file_size_mb ファイルの最大サイズ(超えるとローテーションが発生する) 0 0~2147483647
log_file_rotate_count ローテーションで管理する世代数 1 0~2147483647

9.4   local_configテーブル

アプリケーションが要求するコネクションごとに切り替え可能な設定を格納した テーブルです。アプリケーションがコネクションを生成する際にコンフィグレー ション識別子を指定することができ、本テーブル内に格納された該当識別子 が持つコンフィグレーション名とコンフィグレーション値をもとに、各コネク ションの動作が決定します。

(コンフィグレーション名・コンフィグレーション値の詳細は次節参照)

カラム名 概要 動作中変更可否
configid コンフィグレーション識別子 ×
key コンフィグレーション名 ×
value コンフィグレーション値 ×

9.4.1   初期状態における設定値

configid, keyカラムの格納値 valueカラムの格納値 デフォルト値 範囲 動作中変更可否
DEFAULT, api_exec_timeout API実行時タイムアウト 600 0~2147483647 ×
DEFAULT, fast_api_return_on_db_fail API実行中に同一の系でエラーが発生した場合、即時にエラーとする 1 0, 1 ×

9.5   broken_log_detailテーブル

PostgresForestJDBCが、いずれかのサーバ上のユーザデータベースに不整合状態 が発生したと判断した(すなわち縮退した)際に、不整合が発生したと判断した エラーと、それに関連する各種情報を格納するテーブルです。

カラム名 概要
serverid 縮退となったサーバID
time 縮退発生時の時刻(PostgreSQL内生成時刻)
client 縮退となったアクセス元PostgresForestJDBCドライバの存在するIP(複数IPを持つ場合は列挙される)
api_task 縮退となった際に実行していたAPI(XXXX_Taskの形で出力)
err_msg 縮退エラーのメッセージ文字列
err_type 縮退エラーの例外型
err_state 縮退エラーのSQLステート文字列
err_query エラーとなったSQL(未実装のため常に出力されない)
err_stack 縮退と判断した時点でのPostgresForestJDBC内部スレッドのスタックトレース
app_thread 縮退と判断した呼び出し側スレッドのスレッド名
app_stack 縮退と判断した時点でのPostgresForestJDBC呼び出し側スレッドのスタックトレース

PostgresForestJDBCは、このテーブルに対して縮退発生時に追記するのみです ので、レコード数が増えすぎた場合には管理者がレコードを削除する必要が あります。

9.6   broken_logビュー

broken_log_detailテーブルのうち、スタックトレースなどの、表示上大きく なってしまう部分を削ったビューです。

カラム名 概要
serverid 縮退となったサーバID
time 縮退発生時の時刻(PostgreSQL内生成時刻)
client 縮退となったアクセス元PostgresForestJDBCドライバの存在するIP(複数IPを持つ場合は列挙される)
api_task 縮退となった際に実行していたAPI(XXXX_Taskの形で出力)
err_msg 縮退エラーのメッセージ文字列
err_type 縮退エラーの例外型
err_state 縮退エラーのSQLステート文字列
err_query エラーとなったSQL

10   動作設定

PostgresForestJDBCドライバの動作は、管理情報データベース中に含まれる 設定値を参照して動作を決定しています。ここでは設定値の変更方法と、特に わかりにくい・注意すべき設定項目について記述します。

10.1   設定変更の方法

PostgresForestJDBCの動作設定のうち、管理情報データベースで定義された 設定内容を変更するには、 psql などのコマンドを使用して直接管理情報 データベースを更新します。

例(管理情報読み込み間隔を変更する場合):

psql -h 192.168.1.100 -p 5432 -d userdb_pghainfo -c "update global_config set mngdb_read_duration = 30"
psql -h 192.168.1.101 -p 5432 -d userdb_pghainfo -c "update global_config set mngdb_read_duration = 30"

上記のように設定することで、PostgresForestJDBCドライバは(次の管理情報 読み込みが行われた段階で)この情報を読み込み、管理情報読み込み間隔を 30秒に変更して動作をすることになります。

設定変更を行う場合、双方のPostgreSQL上の管理情報データベースに同じ設定 を施す必要があります。管理情報データベースの global_configlocal_config は、どちらのPostgreSQLサーバから情報を読み込むかは 動作時までわかりませんので、必ず双方のPostgreSQLサーバ上の管理情報データ を変更してください。

注:PostgresForestJDBCドライバが動作中に設定を書き換えることができる のは、global_configテーブルのみです。server_infoテーブルやlocal_config テーブルを動作中に変更した場合の動作は未定義です。

10.2   注意が必要な各種設定

各種設定値は、 管理情報データベース仕様 を参照してください。ここでは 特に注意・理解が必要な設定項目について記述します。

10.2.1   管理情報読み込み間隔

global_configテーブルmngdb_read_duration 列の値によって、 管理情報の定期更新時間間隔が設定できます。この時間間隔で、管理情報の 定期読み込みが行われるため、管理情報データベース上の各種設定を変更した 場合には、最低限この時間が経過した後に、PostgresForestJDBCドライバが 変更後の設定値で動作するようになります。

この設定値が0となっている場合、PostgresForestJDBCドライバは管理情報の 定期読み込みを実施しません。

注意:PostgresForestJDBCドライバが動作中に、1度でもこの設定値を0 (あるいは負数)とした場合、そのPostgresForestJDBCドライバは管理情報 の定期読み込み処理を完全に停止します。一度アプリケーションを停止する などしてPostgresForestJDBCドライバの動作を停止しない限り、管理情報の 再読み込みは行われなくなります。

以下の制限が許容できる場合、この設定値を0とすることができます。

  • PostgresForestJDBCドライバが動作しているJava Virtual Machine がただ 1つのみであることを保障できる環境であること
  • オンラインリカバリ機能を使用する必要がないこと
  • PostgresForestJDBCドライバが動作中に設定値を動的に変更する必要がない こと

10.2.2   縮退対象エラーの設定

PostgresForestJDBCドライバは、双方のPostgreSQLに対してアクセスをする中 で縮退させるべきエラーが発生した場合に、そのエラーが発生したユーザデータ ベースに不整合が発生したとして、縮退処理を行います。

どのエラーを受け取った時に縮退とするかを決定するのが、 global_configテーブルbroken_error_prefix です。

デフォルト(管理情報データベースを作った直後)の値は 08,53,57P,3D となっています。この値は、PostgreSQLから返されるエラーコードの値の うち、縮退としたいエラーコードの先頭部分をカンマ区切りで列挙したもの です。

デフォルト値の場合であれば、``08xxx`` (接続の異常)、 53xxx (リソース不足)、 57Pxx` (外部コマンドによる接続拒否)、 ``3Dxxx (データベースが存在しない) といった場合に縮退処理を行います。

この値は、基本的に変更する必要はありませんが、特定の問題が発生しやすい 環境であり、その場合には縮退をさせたくない、あるいは縮退をさせたい、 といった場合にカスタマイズが可能です。但しその場合には、影響について 十分に考慮する必要があります。

例えば、テーブルが存在しない場合に返るエラー 42P01 を縮退対象に 含めた場合と含めない場合の影響について考えてみましょう。

  • 含めた場合

    この場合、仮にあるテーブルにアクセスできなかった場合には、その PostgreSQLサーバ上のユーザデータベースに不整合があると判断して縮退を 行うことになります。オペレーションミスなどで、片方のPostgreSQLサーバ 上のテーブルのみを削除してしまった場合、そちら側のPostgreSQLサーバ にはそれ以降アクセスしなくなり、もう片方のサーバのみで処理を継続する ため、アプリケーションには影響が出ません。

    しかしながらアプリケーションの開発中などは、テーブル名を間違えてアク セスするなどケースが考えられます。。また、テーブルを動的に変更する アプリケーションの場合、動作最中にテーブルが無くなることは十分考え られます。こういった事態が発生するたびに、縮退が発生してしまいます。

  • 含めない場合

    この場合、仮にあるテーブルにアクセスできなかった場合に、それ自体には 問題ないと判断して縮退処理を行いません。動的にテーブルを変更しうる アプリケーションなどの場合には、この設定にしないと頻繁に縮退が発生 してしまいます。

    しかし、オペレーションミスなどで片方のPostgreSQLサーバ上のテーブルを 削除してしまった場合などには問題が発生します。テーブルが無い方の ユーザデータベースにアクセスし続けるものの、削除してしまったテーブル には当然アクセスできないため、アプリケーションはエラーを返されること になってしまい、アプリケーションとして処理継続ができなくなってしまう 可能性があります。

10.2.3   APIの実行タイムアウト

ネットワーク回線が経路の途中で物理的に切断された場合や、通信対象のマシン が突然電源断した場合など、その検出に非常に時間がかかります。これは、OS のソケット実装仕様・設定によります。``RedHat Enterprise Linux5``の標準 状態では、検出までに数十分かかります。

PostgreSQLのJDBCドライバの場合、アプリケーションからのAPI実行時にネット ワークの無応答が発生した場合、OS側で検出するまで完全に応答がなくなって しまい、アプリケーションが停止します。

PostgresForestの場合、OS側でのネットワーク異常の検出機構だけでなく、 PostgresForest独自にタイムアウトの設定を設けることによって、より迅速に ネットワーク無応答に対応できるようになります。この時間設定が、 local_configテーブル の、``query_exec_timeout`` パラメータです。

この設定値は、PostgreSQLにアクセスする全てのAPI実行時に同一のタイムアウ ト時間を設定します。

11   PostgresForestでできないこと

11.1   対応できない障害

11.1.1   SQL実行時間が非常に長い環境でのネットワーク障害

ネットワークの切断などに対して、OSが異常を検知するまでには時間がかかり ますが、PostgresForestの場合は独自のタイムアウトをもうけることによって より迅速にネットワーク障害を検出して縮退処理を行うことができる、という ことは APIの実行タイムアウト に記述したとおりですが、SQLの実行時間が 非常に長い場合、あるいはSQLの実行時間が全く見積もれないようなデータ内容 の場合、このパラメータによってネットワーク無応答に類する障害への対応 時間を短くすることが困難になります。APIの実行時間の設定値よりも実行に 時間がかかると、異常が発生したと認識して縮退するためです。

そのため、このような場合にはAPIの実行時間の設定を行わず、OS側でネット ワーク障害を検知させます。OS側で障害を検知するまで、PostgresForestは 無応答になってしまいます。

OSのレイヤでネットワークの障害をより早く検知するためには、カーネルの パラメータを変更する方法がありますが、そのホスト上の全てのネットワーク アプリケーションに影響が出ることを認識する必要があります。

11.1.2   スプリット

下図のようなネットワーク構成で、HUB1とHUB2を繋ぐネットワークが故障した 場合には、PostgresForestクラスタはデータベース全体として不整合を発生 させることになります。

┌───┐        ┌───┐
│Host1 │        │Host2 │
│(App1)│        │(App2)│
└─┬─┘        └─┬─┘
    │                │
┌─┴─┐        ┌─┴─┐
│ HUB1 ├────┤ HUB2 │
└─┬─┘        └─┬─┘
    │                │
┌─┴─┐        ┌─┴─┐
│Host3 │        │Host4 │
│(PG1) │        │(PG2) │
└───┘        └───┘

HUB1とHUB2の間のネットワークが故障した場合、Host1上のアプリケーション (PostgresForestJDBC)は、Host3のPostgreSQLのみにアクセス可能なため、 Host3のPostgreSQL上のユーザデータベースにのみアクセスし続けます。 対して、Host2上のアプリケーション(PostgresForestJDBC)は、Host4の PostgreSQLのみにアクセス可能なため、Host4のPostgreSQL上のユーザデータ ベースにのみアクセスし続けます。結果として、双方のアプリケーションが 各々に孤立した情報を参照・更新し続けてしまい、データベースとしての 整合性がなくなってしまいます。

11.2   縮退発生時の不整合発生可能性

以下に想定するような事象が発生した場合に、一時的にデータベースとしての 不整合が発生する可能性があります。

┌───┐        ┌───┐
│Host1 │        │Host2 │
│(App1)│        │(App2)│
└─┬─┘        └─┬─┘
    └──┐    ┌──┘
        ┌┴──┴┐
        │  HUB   │
        └┬──┬┘
    ┌──┘    └──┐
┌─┴─┐        ┌─┴─┐
│Host3 │        │Host4 │
│(PG1) │        │(PG2) │
└───┘        └───┘

上図のうち、Host1のファイアウォールの設定で、Host4へのアクセスを一時的 に不許可にしてしまった場合、Host1上で動作するPostgresForestJDBCドライバ (App1)は、Host4側を縮退とします。そのため、Host3の管理情報にはHost4が アクセス対象外になった(縮退した)ことが書き出されます。

しかし、Host2上のPostgresForestJDBCドライバ(App2)はHost4に問題なく アクセスできてしまいます。そのためApp2は、次に管理情報の定期読み込みを するまでHost4の障害を知ることができず、Host4にアクセスし続けてしまうこと になります。

つまりこの例で、App2は最大で 管理情報読み込み間隔 に示した読み込み 間隔(デフォルトでは10秒)の間、App1からは更新されていないHost4側の ユーザデータベースにアクセスしてしまうことになります。

PostgresForestJDBCドライバを使用するアプリケーションが、ただ1つのJava プロセスとして動作している(すなわち1つのホスト上の1つのJavaプロセス 上でのみ動作している)場合であれば、この問題は発生しません。 また、本当のディスク障害・インスタンス障害など、どのJavaプロセスからも まったく同じように障害と認識される場合には、上記のような問題は発生しま せん。

多数のJavaプロセスがPostgresForestJDBCドライバを使用して同一の PostgresForestクラスタ環境にアクセスしている場合には、上記のような種類 の不整合が発生することを抑止することはできません。そのためこうした不整 合の発生を許容できないアプリケーションでは、PostgresForestの使用は推奨 できません。

11.3   同一行を頻繁に更新するアプリケーション

同一行を頻繁に更新するアプリケーションの場合、ノード間デッドロックの 問題が多発する可能性があります。この問題が多発している場合、アプリケー ションのつくりにもよりますが、一般的には

  • エラーが頻発する
  • 処理が異常に遅くなる
  • そもそも処理が全く進まない

等の症状が出る可能性があります。PostgresForestでは、この問題を回避する ことはできません。同一行を頻繁に更新するアプリケーションでは使用しない ようにしてください。