Microsoft.Data.SqlClient を使用した SQL Server の接続プーリング

Microsoft。Data.Sqlクライアント接続プーリングは認証済みの物理接続を再利用します。 SqlConnection.Open または OpenAsync は、プール内で使用可能な接続を確認します。 CloseDispose、または DisposeAsync がリセットして返します。 この方法は、すべての操作でネットワーク接続、認証、セッション設定を回避できます。

プーリングはデフォルトで有効になっています。 以下の適用パターンをご利用ください:

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);

using var command = new SqlCommand(sql, connection);
await command.ExecuteNonQueryAsync(cancellationToken);

遅めに開店し、早めに処分し、プールに物理的な接続を任せましょう。 世界中で一つの SqlConnection を開けておくのはやめましょう。

プールキーを理解する

接続は、その接続に対応するプールからのみ再利用できます。 プールキーは宛先サーバー以上のものを含みます。

Input プールの挙動
接続文字列 テキストは完全に一致しなければなりません。 キーワードの順序の違いが、効果設定が同等であっても別々のプールを生み出します。
Windows 統合認証 Windowsのアイデンティティはキーの一部です。 同じ文字列を異なる識別子の下で使用すると、異なるプールが作成されます。
SqlCredential オブジェクトインスタンスはキーの一部です。 別々のインスタンスは、同じユーザー名とパスワードを含んでいても別々のプールを作成します。
SqlConnection.AccessToken アクセストークンの値も鍵の一部です。 トークン文字列を置き換えることで新しいプールが作成され、既存のプールで古いトークンで認証された接続を残すことができます。
SqlConnection.AccessTokenCallback コールバックはキーの一部です。 プールを共有するはずの接続には同じコールバックインスタンスを再利用します。 返されたトークン値はプールキーではありません。
カスタムSSPIコンテキストプロバイダー プロバイダーインスタンスは接続設定に参加します。 同じプールにまとめるべき接続には、1 つのプロバイダー インスタンスを再利用してください。
アンビエントトランザクション 登録された接続はマッチングプール内でトランザクション固有の細分化を使用します。

データベース、認証モード、暗号化オプション、アプリケーション名、プーリングオプション、その他すべての接続文字列値が正確な文字列を通じて寄与します。

1つの標準的な接続文字列を作り、それを再利用します。 Application NameWorkstation ID、その他のキーワードでのリクエストごとの値は避けてください。

プール可能なトークンAPIを選びましょう

Microsoft Entra ID アクセス トークンには、Microsoft.Data.SqlClient によって提供される認証モードまたは安定版のAccessTokenCallbackを使用してください。

AccessTokenCallbackは Microsoft.Data.SqlClient 5.2 で導入されました。 ドライバーはトークンが必要なときに呼び出し、再利用プールのために更新されたトークンを要求できます。 ドライバが提供する認証パラメータのコールバック決定性を維持し、同じデリゲートインスタンスを再利用します。

コードが AccessToken を直接設定する場合:

  • トークン文字列はプールキーの一部となります。
  • アプリケーションはトークンの有効期限と更新を所有しています。
  • プールされた物理接続は、それを作成する際に使われたトークンよりも長く使われることがあります。
  • 期限切れのトークンを交換した後、そのプールが安全に使えなくなった場合は ClearPool に電話してください。

すべてのリクエストごとに新しいコールバックラムダや資格オブジェクトを作成しないでください。 オブジェクト識別子の違いはプールを断片化させることがあります。

Microsoft.Data.SqlClient 7.0 では、カスタム Kerberos または NTLM 認証ネゴシエーション向けの SspiContextProvider が追加されました。 プロバイダーはリクエストごとの状態ではなく、アプリケーションスコープ接続構成として扱ってください。

各プールのサイズ

これらの 接続文字列 オプションは 1 つのプールを制御します:

キーワード Default Effect
Pooling true プーリングを有効または無効にします。
Min Pool Size 0 プール作成後に保持する物理接続の最小数を設定します。
Max Pool Size 100 プール内の物理接続の最大数を設定します。
Connect Timeout 15 秒 使える接続が Open ないときにどれだけ待つかを設定します。
Load Balance Timeout 0 接続は、プールに戻る際に、その使用期間が設定値を超えている場合は破棄されます。 Connection Lifetime はエイリアスです。

需要が増加するにつれてプールは接続を生み出し、最終的に Max Pool Sizeに達します。 すべての接続が使用中の場合、後で開くユーザーは接続の戻りを待ちます。 待ち時間が Connect Timeoutを超えると、オープンは失敗します。

確認する前に Max Pool Size 上げないでください:

  • すべての接続とリーダーは、各パスで破棄されます。
  • コマンドやトランザクションは迅速に完了します。
  • クエリのワークロードはブロックされたり飽和したりしていません。
  • データベース接続の上限は、すべてのアプリケーションインスタンス内の各プールに対して Max Pool Size を掛けた数まで対応できます。

正の Min Pool Size は、アイドル時間でも接続を開いたままにします。 測定結果が温かい接続に値する場合にのみ使用してください。 通常、スケール・トゥ・ゼロ、サーバーレスの自動一時停止、バースト可能なクラウド設計に対して効果的です。

デフォルトの Load Balance Timeout=0では、定期的なクリーンアップで Min Pool Size 以上の未使用接続が約4〜8分後に削除されるか、サーバー接続が切断されたと検出するとプールが削除します。 その区間は、接続ごとのアイドル保証ではなく、実装動作として扱ってください。 プールは毎回のチェックアウト前に検証クエリを送信しません。なぜなら、往復の移動がプールのメリットを多く失わせるからです。

認証ブロック期間の管理

認証タイムアウトやその他の認証失敗の後、プールはブロッキング期間に入ることがあります。 その期間中、マッチングオープン試行は再度認証試行を行うことなく元の例外を投げ戻します。

最初のブロッキング時間は5秒です。 また失敗すると、その時間は1分に倍になります。

Pool Blocking Period この挙動を制御します:

価値 Behavior
Auto 通常のSQL Serverエンドポイントに対してブロッキングを有効にし、認識されたAzure SQLエンドポイントのサフィックスに対しては無効化します。 バニティDNS名はAzureの動作を受け取らない場合があります。
AlwaysBlock すべてのエンドポイントでブロッキング期間を有効にします。
NeverBlock ブロック期間を無効にします。

アプリケーションの測定されたリトライ設計が異なる選択を要求しない限り Auto 続けてください。 ブロック期間を無効にすると、認証情報、ファイアウォール、障害の問題が認証ストームに変わる可能性があります。

ブロッキング期間は設定可能な再試行ロジックとは別物です。 ブロック期間中に同じプールを開いたリトライプロバイダーはキャッシュされた例外を受け取ります。

接続の寿命とクリアリングを管理する

フェイルオーバーなどの致命的なエラーを認識すると、プールは自動的に影響を受けたプールをクリアします。 プールはアイドル接続を閉鎖し、チェックアウトされた接続は戻ってきたら破棄します。

既知の設定や認証情報の境界に対してクリアリングAPIを活用します:

  • ClearPool 1つの SqlConnection 構成に関連付けられたプールをクリアします。
  • ClearAllPools は、プロセスまたはアプリケーション ドメイン内のすべての Microsoft.Data.SqlClient プールをクリアします。

プールは、クリア済みのプール内のアイドル状態の接続を閉じます。 プールは現在使用中の接続をマークしておき、返却された際にそれらを破棄します。

プールをクリアすると、以後のオープンでは実際のログイン処理が必要になります。 定期的なメンテナンスや一般的なエラー処理ツール、接続の廃棄の代替として使わないでください。

Load Balance Timeout 年齢に応じた段階的な離職率を提供します。 デプロイメントやクラスタサービスが古い物理接続を時間とともに離れる必要がある場合に使います。 選択した値が過剰なハード接続を引き起こしていないか確認してください。

トランザクションを理解する

デフォルト Enlist=trueでは、 System.Transactions.Transaction.Current 内で開かれた接続が自動的にそのトランザクションに登録されます。

登録された接続が閉じると、プールはそれをトランザクション固有の細分化に配置します。 同じトランザクション内で後から行う open では、それを再利用できます。 物理的な接続はトランザクションが完了するまで一般プールに戻りません。

そのため、長時間継続している、または放棄されたアンビエント トランザクションは、次のような問題を引き起こす可能性があります:

  • 物理的な接続は共通プールから除外しておきましょう。
  • 論理接続が終了した後にプール容量を消費します。
  • サーバーロックとトランザクションステートを常に維持しましょう。

トランザクションは適切な範囲内に保ち、明示的に完了させ、停滞した接続を監視してください。 接続がアンビエントトランザクションの外に留まる必要がある場合にのみ Enlist=false 設定します。

プール断片化の防止

プールの断片化は、いくつかの再利用可能なプールではなく、多くの小さなプールを生み出します。 一般的な原因には、次のようなものがあります。

  • 接続文字列、キーワードの順序、またはエイリアスの違い。
  • 顧客、ユーザー、リクエスト、またはデータベースごとに1つの接続文字列を割り当てます。
  • 多くのWindowsアイデンティティで統合認証。
  • 新しい SqlCredential、アクセストークンコールバック、またはリクエストごとのSSPIプロバイダーインスタンス。
  • リフレッシュごとに変更されるダイレクトアクセストークン。
  • 高カーディナリティのアプリケーション名やワークステーションIDなどです。

接続文字列を SqlConnectionStringBuilder で正規化し、接続作成を集中管理します。

アプリケーションが意図的に多くのデータベースやアイデンティティに接続する場合は、得られたプール数を容量計画に含めてください。 信頼できないデータベース名で USE を実行してプールを崩壊させないでください。 データベースの分離、権限、セッション状態、プールリセットの挙動は明示的に保たなければなりません。

アプリケーションの役割とセッション状態を考慮します

プールは物理接続を別の論理接続に割り当てる前に、再利用可能なSQL Serverセッションの状態をリセットします。 アプリケーションコードは、その作業単位内で必要なセッション状態を設定するべきです。

sp_setapproleでアクティベートされたSQL Serverアプリケーションロールは通常のプーリングでは安全にリセットできません。 データベースユーザー、包含ユーザー、ロール、行レベルのセキュリティ、またはその他の認可設計を優先します。 アプリケーションロールが避けられない場合は、ドキュメント化されたクッキーベースのリバーサルパターンを使用するか、テスト後にその分離パスのプーリングを無効にしてください。

リーダーを廃棄し、トランザクションを終了またはロールバックし、接続が終了したときにコマンドをそのままにしないようにしましょう。 一時テーブルや他のセッション状態が論理接続間で生き残ることに頼らないでください。

クラウドホスト型プーリングパターンを活用してください

Azure App Service、Azure Functions、コンテナー、Kubernetes、およびその他の水平スケールされたホストの場合:

  • すべてのインスタンス、プロセス、プールキー、レプリカ間で可能なデータベース接続を計算します。
  • 管理型アイデンティティや安定したアクセストークンのコールバックを使い、接続オブジェクト内のトークン文字列をローテーションする代わりに活用しましょう。
  • 測定に基づくコールドスタート要件によってセッションの保持が正当化される場合を除き、Min Pool Size=0 のままにしてください。
  • 新しいインスタンスは、空のプールで開始されることを想定してください。
  • 同じワークロードに対応するインスタンス間で接続文字列を同一に保ちましょう。
  • フェイルオーバー時やスケールアウト時にログイン要求が集中しないよう、接続試行回数と再試行回数を制限します。
  • Azure SQLおよび他の対応するマルチアドレスTCPエンドポイント用にMultiSubnetFailover=trueを設定してください。

接続プールは申請プロセスにローカルで存在します。 それらはアプリケーションインスタンス、コンテナ、ホスト間で共有されていません。

プールの挙動を診断する

SqlClientの診断カウンターを使って観察します:

  • ハードコネクトとディスコネクトは物理的なサーバー接続を表します。
  • ソフトコネクトと切断はプールのチェックアウトとリターンを表します。
  • アクティブおよびフリープールされた接続。
  • アクティブなプールグループとプール。
  • スタシス接続。
  • アプリケーションコードが論理接続を解放しなかったために回収された接続。

クライアントカウンターをSQL Serverセッション、待ち時間、ブロッキング、リソース制限と関連付けます。 プールのタイムアウトは、接続漏れ、クエリの遅延、トランザクションのブロック、並行性の過剰、プールの断片化、またはデータベース容量の制限を意味することがあります。

対象を絞ったプーラーのトレースには イベントソーストレーシング を使用してください。 トレースは冗長です。 それを期間を限定した診断ウィンドウでのみ有効にし、取得した接続メタデータを保護してください。

実稼働チェックリスト

  • プーリングを有効にしたままにしてください。
  • ワークロードとデータベースごとに1つの標準的な接続文字列を再利用します。
  • すべてのパス上で接続、コマンド、リーダー、トランザクションを処分します。
  • 認証情報、トークンコールバック、SSPIプロバイダーインスタンスを再利用します。
  • 接続時間とコマンドタイムアウトを設定しましょう。
  • すべてのアプリケーションインスタンスで総接続予算をサイズ化しましょう。
  • ハード接続数、プール数、空き接続数、停止状態、タイムアウトを監視してください。
  • プロバイダーが検出できない資格情報、トークン、または設定境界がある場合、または診断で古い接続が確認された場合のみプールをクリアします。
  • 本番環境の前に、スケールアウト、フェイルオーバー、認証情報のリフレッシュ動作をロードテストしてください。