はじめに
開発環境やステージング環境は、本番環境で直面するであろう多くの状況を予測するのに役立ちますが、一部の課題は規模が大きくなって初めて表面化し始めます。データベース接続管理はまさにこのカテゴリに分類されます。クライアントインスタンスからのリクエスト数は、データベースソフトウェアがサポートする接続制限をすぐに超えてしまう可能性があります。
長いキュー時間、失敗したリクエスト、ユーザーに影響を与えるエラーを防ぐために、このリソース競合に対処するには接続管理ポリシーとツールが必要です。コネクションプーリングは、データベース接続を管理および再利用するための中間キューイングシステムをデプロイする戦略であり、これらの問題を軽減するためにしばしば成功裏に採用されます。
このガイドでは、コネクションプーリングとは何か、それが対処しようとする具体的な条件、そしてその仕組みについて説明します。代表的な例としていくつかの一般的な実装を紹介し、クライアントのリクエストがデータベースの利用可能な接続数を上回った場合に、それらがクライアントの動作をどのように変化させるかについて議論します。
コネクションプーリングは、Prisma Accelerate が Prisma Data Platform で提供するコア機能の1つです。Prismaを使用してデータベースを操作している場合は、無料プロジェクトを開始して、接続を簡単に管理し、データを閲覧できます。
データベース接続を開くには何が必要か?
接続管理全般とコネクションプーリング具体的にについて話す前に、データベース接続中に何が起こるかを詳しく見ておくことが役立つかもしれません。
クライアントアプリケーションがデータベースへの接続を開くには、驚くほど多くのステップが発生する必要があります。各接続について、以下のステップの一部またはすべてが発生する必要があります。
- データベースサーバーのIPアドレスを特定するために必要なDNSルックアップ
- サーバーへのTCP接続を確立するために必要な3ウェイハンドシェイクの実行
- TLSハンドシェイクを介して接続の暗号化を交渉し有効にする
- セッションパラメータを確立するためにデータベースソフトウェアと設定と要件を交換する
- クライアントの身元を確立するためにデータベース認証チェックを実行する
- クライアントが要求されたデータベースオブジェクトにアクセスできることを確立するために最初の認可チェックを実行する
- 実際のクエリを実行し、結果を返す
- データベースセッション、TLS暗号化、およびTCP接続を終了する
接続数がデータベースサーバーのリソースにどのように影響するか?
上記すべてを完了するのに必要な時間に加えて、各接続は確立および維持するためのリソースも必要とします。例えばPostgreSQLでは、いくつかのテストされたワークロードでは、接続あたり1.5~14.5MBのメモリが使用されました。
サーバーが各新規接続の状態を管理する必要があるため、接続数が増えるにつれてCPU使用率も上昇します。接続管理により多くのメモリとCPUが使用されるようになると、トランザクションが実行できるレートなど、他の事柄に影響を与え始める可能性があります。多数の接続を管理するオーバーヘッドは、データベースシステムが結果を最適にキャッシュする能力を妨げ、有用な作業を実行する能力を低下させます。
接続数はクライアントアプリケーションにどのように影響するか?
上記の段落ではデータベースサーバーが支払う接続コストについて説明していますが、クライアントにも直接的な影響があります。データベースサーバーは、特定の数の接続のみを受け入れるように構成できます。その制限に達すると、追加の接続リクエストは拒否されます。
これは、デフォルトでは、クライアントコードがこれらの失敗を処理するために、指数関数的バックオフアルゴリズムを使用してリクエストを繰り返すロジックを実装する必要があることを意味します。しかし、さらに重要なことは、クライアントがその機能を頻繁に使用せざるを得なくなり、クエリの停止、遅延、そしてユーザーにすぐに影響が及ぶ問題につながる可能性があることです。
仲介する中間コンポーネントがなければ、以下の点を考慮せざるを得なくなるでしょう。
- データベースサーバーの接続制限を増やすこと(データベースサーバーのメモリとCPU使用量、およびトランザクションレートに影響を与える)、
- データベースをスケールアップして、より多くのメモリ、CPU、またはネットワーク容量を割り当てること、または
- データベースをスケールアウトして、より多くのマシンにリクエストを分散すること
これらの選択肢自体が必ずしもマイナスであるとは限りませんが、ここで説明している種類の輻輳(ふくそう)に対しては過剰になる可能性があります。コネクションプーリングは、現在持っているリソースをより有効活用するのに役立つ代替手段です。
コネクションプーリングとは?
コネクションプーリングは、クエリが解決されたときにデータベース接続をすぐに閉じるのではなく、複数のリクエストで再利用する戦略です。通常、これはデータベースサーバーとそのクライアントアプリケーションの間にコネクションプーラーと呼ばれるソフトウェアを導入し、両者間の接続を管理することで行われます。
前述したように、接続を確立する際には、データベースサーバーが実際にクエリを実行する前に、かなり長い一連の操作を実行する必要があります。コネクションプーラーは、最初のクエリの後に接続を開いたままにしておくことで、これらの操作のコストを償却し、追加のクエリを実行するために再利用しようとします。
このシステムでは、クライアントはデータベースに直接ではなく、コネクションプーラーに接続します。クライアントはプーラーをデータベース自体であるかのように扱い、プーラーはクエリを解釈して適切な接続をクライアントに渡します。注意すべき点は、クライアントとプーラー間の接続の開閉には依然としてオーバーヘッドがあるということです。ただし、これらの接続は、重い処理の大部分がデータベース自体への接続を確立する際に発生するため、通常はオーバーヘッドが低くなります。
コネクションプーリングはどのように機能するのか?
コネクションプーラーは、クライアントに代わってデータベースへの接続を開閉し、維持する責任があります。これは、キャッシュシステムが使用するようなアルゴリズムに従って行われます。
クライアントがコネクションプーラーに接続して接続を要求すると、プーラーはリクエストの特性を迅速に評価します。データベースユーザー、実行される具体的な操作、暗号化の種類、アクセスされるデータベースオブジェクトなどの情報を確認する場合があります。
この情報が得られると、プーラーは利用可能な接続のプールを調べ、新しいリクエストを実行するために使用できる既存の接続があるかどうかを確認します。適切で利用可能な接続が見つかった場合は、それをクライアントに渡し、その接続を介してクエリを実行させます。新しいリクエストの実行に適した接続がプールに存在しない場合は、必要なパラメーターを使用してデータベースに新しい接続を開き、それをクライアントに渡します。
クライアントは通常通り接続を使用してクエリを実行します。クエリが完了すると、プーラーは接続を終了する代わりに、接続をプールに戻し、その後のクエリで再利用できるようにします。プーラーは、選択したアルゴリズム(確立からの時間、最終使用からの時間など)を使用して、プール内の接続を非同期的にガベージコレクションできます。
内部プールと外部プールの違いは何か?
広く言えば、コネクションプーリングとは、複数のリクエストにわたって接続を維持するアルゴリズムを指します。これは、クライアントアプリケーションの内部で実装することも、外部ツールやサービスを使用して外部で実装することもできます。
コネクションプーリングの内部実装は、データベースドライバー、ORM(オブジェクトリレーショナルマッパー)、またはクライアントアプリケーションに組み込まれる可能性のある他のデータベースクライアントの機能であることがよくあります。これらのソリューションは、データベースサーバーへの長期接続を維持し、コードベース内で複数のクエリにそれらを再利用することで、コネクションプーリングの利点の一部を提供します。
内部コネクションプーリングは便利ですが、いくつかの実用的な制限があります。実行されているアプリケーションの各インスタンスは、通常、独自のプールを維持する必要があります。各プールは単一のアプリケーションインスタンスのみを処理するため、これによりクエリ間で接続をどの程度広範に共有および再利用できるかに影響します。
代替ソリューションは、外部コネクションプーリングを実装することです。このアプローチでは、複数のクライアントインスタンスとの通信と接続のプールを可能にする別のソフトウェアを展開します。このデプロイシナリオは追加のネットワークホップを導入しますが、一般により高いスケーラビリティと柔軟性を提供します。コネクションプーラーは、多くの異なるクライアントにサービスを提供するためにデータベースサーバーと並行してデプロイすることも、単一サーバーで実行されているアプリケーションインスタンスにサービスを提供するためにクライアントアプリケーションと並行してデプロイすることもできます。
一般的な外部コネクションプーラーにはどのようなものがあるか?
さまざまなデータベースシステムで利用できるコネクションプーラーは多数あります。PostgreSQLで利用可能ないくつかの実装を見て、異なるソリューションが問題にどのようにアプローチするかをよりよく理解できます。
pgbouncer
PostgreSQLで最もよく知られているコネクションプーラーは、おそらくpgbouncer
でしょう。
2007年に作成されたpgbouncer
は、PostgreSQL接続を管理するための軽量なプーリングメカニズムの提供に焦点を当てています。デプロイ場所とプーリングの実行方法の両方において、かなりの柔軟性を提供します。
クライアントからの接続が短命な状況では、プロジェクトは、クライアントコードが実行されるWebサーバーにpgbouncer
をデプロイすることを推奨しています。プーラーをクライアントソフトウェアと一緒に配置することで、両者間の接続がTCPよりも軽量なメカニズムを使用できるようになり、レイテンシが削減されます。多くの異なるクライアントからの接続をまとめてプールする必要があるシナリオでは、代わりにデータベースサーバーと並行してデプロイできます。
pgbouncer
を使用する上で最も重要な決定の1つは、使用するプーリングモードを選択することです。利用可能な3つのオプションは以下の通りです。
- トランザクションプーリング: クライアントによる各トランザクション後に接続が取り消されます。その後のトランザクションでは、接続が再度割り当てられます。これにより、クライアントがトランザクション間で他の操作を実行している間に、
pgbouncer
が接続を迅速に再利用できます。 - セッションプーリング: 接続は、クライアントがプーラーと接続している期間中、クライアントに割り当てられます。これは、各クライアント接続がデータベースへの専用接続とペアになることを意味します。クライアントセッションが終了すると接続は再利用されますが、一度にプーラーを使用できるクライアントの数は大幅に減少します。
- ステートメントプーリング: 接続は個々のステートメントを実行するために割り当てられます。これにより、接続の割り当てと解放が迅速に行われ、多くのクライアントが限られた数の接続を使用できますが、トランザクションセマンティクスを破壊し、場合によっては予期しない動作につながる可能性があります。
ほとんどの場合、トランザクションプーリングは、アイドル接続の再利用、適切な数のクライアントの管理、およびデータベースセッションとトランザクションセマンティクスに関する期待される動作の維持に関して、最良のバランスを提供します。
pgpool
もう1つのPostgreSQLコネクションプーラーはpgpool-II
で、しばしば単にpgpool
と呼ばれます。pgbouncer
がコネクションプーリングに特化した軽量ツールであるのに対し、pgpool
はより幅広い関連機能を提供します。
コネクションプーリングに加えて、pgpool
は複数のバックエンドデータベースインスタンス間のクエリのロードバランシングをサポートし、自動フェイルオーバーのための高可用性運用を可能にするウォッチドッグサービスを備えています。さらに、特定のデプロイシナリオで非常に役立つ管理GUIも提供します。
これらの高度な機能にもかかわらず、pgpool
は実際のコネクションプーリングの管理に関しては、やや制限があると通常見なされています。pgbouncer
が3つのプーリングモードを許可するのに対し、pgpool
はセッションモードに相当するもののみで動作でき、これはクライアントが切断されたときにのみ接続が再割り当てされることを意味します。これにより、pgpool
が処理できるクライアントの数は比較して減少します。
結論
このガイドでは、コネクションプーリングの概念と、それがデータベース負荷とリソース消費の削減にどのように役立つかについて考察しました。クライアントとデータベース間の接続確立が高価になる理由のいくつかを示し、接続を再利用することでその後のクエリでのコストを削減できることを説明しました。その後、コネクションプーラーが実際にどのように機能するかについて議論し、PostgreSQLエコシステムからのプーラーの代表的な例をいくつか見てみました。
アプリケーションがスケールし、クエリ負荷がより複雑になるにつれて、データベース接続の制限はすぐに問題を引き起こす可能性があります。接続管理に関連するオーバーヘッドを完全に排除することは不可能ですが、コネクションプーラーはパフォーマンスを維持し、データベースがサービスを提供できるクライアントの数を増やすための非常に貴重なツールです。
コネクションプーリングは、Prisma Accelerate が Prisma Data Platform で提供するコア機能の1つです。Prismaを使用してデータベースを操作している場合は、無料プロジェクトを開始して、接続を簡単に管理し、データを閲覧できます。