web-dev-qa-db-ja.com

JavaEEアプリケーションでPostgreSQLホットスタンバイセットアップの接続フェイルオーバーを構成する方法

2つのLinuxサーバー(AおよびB)にPostgreSQL 9.5データベースがインストールされています。 ドキュメント の説明に従ってhot standbyモードを構成しました。このセットアップでは、Aはマスターとして構成され、Bはホットスタンバイモードで構成されます。これは正常に機能し、期待どおりに動作します。

ここで、独立したJava EEアプリケーション(別のマシンで実行)からHibernate/JDBCを介してTomEEデータソースを介してこのデータベース設定に。

PostgreSQLドライバー のドキュメントには、jdbc接続URLで複数のホストを指定できると記載されています。

jdbc:postgresql://Host1:port1,Host2:port2/database

だから私の質問は:

  1. Aがダウンしていて、Bを手動で通常の操作モードに切り替えた場合、アプリケーションは上記のようにjdbc接続URLでデータベース操作を続行できますか?
  2. 他のパラメーター/ライブラリーを構成する必要がありますか?

注:私が学んださまざまなソースから、PostgreSQLは自動フェイルオーバーをサポートしていません(サードパーティのソフトウェアがプロセスに関与している場合を除きます-下記のコメントを参照)。このため、フェイルオーバーは手動で実行する必要がありますが、この特定のユースケースでは問題ありません。

EDIT-1:

(コメントで提案されているように)回避策としてpgBouncerをテストすることにしました。私のユースケースでうまく機能します。手動の手順を自動化するウォッチドッグスクリプトを作成しました。

  1. Aがまだ有効で、着信接続をリッスンしているかどうかを継続的に確認します。
  2. フェイルオーバーが発生した場合は、Bを通常の動作モードに切り替え、それを新しいマスターにしてサービスを再起動します。
  3. pgBouncer設定をBではなくAを指すように変更し、サービスを再起動します。

しかし、誰かがサードパーティのソフトウェアなしで経験を持っているなら、私はまだ興味がありますか?

21
rzo

このような状況では、テストして測定するのがおそらく最善です。

PostrgeSQLホットスタンバイモードの「実地」経験はありませんが、Javaアプリケーションのデータベースフェイルオーバーを実行しました。

まず、?targetServerType=masterパラメータに関する PostgreSQLドライバー ドキュメントページ(ページ下部に記載)の主張をテストします。
小さなJava "PgHsm"クラスを、DriverManager.getConnectionを介してPostgreSQL JDBCドライバーを使用し、単純な更新クエリを実行するmainメソッドで記述します。
サーバーAを使用して更新クエリを実行する必要があります。サーバーAでPostgreSQLを停止し、PgHsmを実行します。サーバーBはマスターではないため、接続に失敗するはずです。
サーバーBをマスターにして、PgHsmを実行します。正常に実行されるはずです。

データソースは、TomEEのデータベース接続プールによってサポートされています。 このページ は、TomEEで利用可能なものをリストします。しかし、すべてのデータベース接続プールが同じというわけではなく、私はHikariCPを好むようになりました。これは、私の経験では、「データベースダウン」シナリオをより予測可能に処理するためです。 HikariCPの データベースの処理 ページの結果を含むテストも参照してください。

残念ながら、HikariCPはJDBCの get/setNetworkTimeout を使用して予測どおりに動作し、PostgreSQL JDBCドライバー これを実装していません (*)を使用しています。したがって、(JavaEE)アプリケーションスレッドがデータベースアクションで永久にハングアップしないようにするには、connectTimeoutおよびsocketTimeout JDBCドライバーオプションを設定する必要があります。 socketTimeoutを設定すると、データベースへのすべてのクエリの時間制限が自動的に設定されるため、危険です。

(*)更新:バージョン42.2.x以降、ネットワークタイムアウトは 実装 です。

実行する2番目のテストでは、Java "PgHsm"クラスを更新して、選択したデータベース接続プールの実装を使用し、(少なくとも)ループで単純な更新クエリを継続的に実行する2つのスレッドを開始します(ループでは、データベース接続がプールから取得され、コミット/ロールバック後にプールに返されます。サーバーAを停止してサーバーBを「マスター」モードに切り替えながら、「PgHsm」によってログに記録された例外と、スレッドはデータベースアクションの実行で待機/ハングします。
テストの結果を使用して、JDBCドライバーオプションとプール設定を更新できます。以下の結果に焦点を当てます:

  • 無効な接続はできるだけ早くプールから削除されるため、アプリケーションはほとんどプールから有効な接続を取得します
  • データベースがダウンしたときに、可能な限り少ないアプリケーションスレッドが(最短時間で)ハングする

2番目のテストは、サーバーAが利用できないため、接続テストクエリ(データベース接続プールによって実行される)が失敗することを前提としています。両方のサーバーが引き続き使用可能であるが、マスタースイッチとスレーブスイッチの場合、接続テストクエリは役に立たず、データベース接続プールはアプリケーションに誤った(現在は読み取り専用)データベース接続を提供します。その場合、手動による介入が必要です。 HikariCPの「フェイルオーバーパターン」は here で説明されています( configuration ページで説明されているオプションallowPoolSuspensionでのみ使用可能):

  • suspendPool()
  • softEvictConnections()
  • ActiveConnectionsが0になるまで待ちます。
  • resumePool()

3番目のテストはJavaEEアプリケーションを使用して行われます。これで、どのような問題が発生するかを理解できるはずです。これらの種類のテストの後にアプリケーションが更新されて「データベースダウン」シナリオの処理が改善されることは珍しくありません(たとえば、設定(デフォルト) query-timeouts )。あなたの場合、手動フェイルオーバー中に使用する「データベース接続プールの一時停止、フラッシュ、および再開」機能(上記のパターン)も望ましいでしょう。

10
vanOekel