2

ADO.NET 上に構築されたアプリケーションがあります。接続プールを利用できるいくつかの簡単なベスト プラクティスに従います。たとえば、データベースを使用するコード ブロックは次のようになります。

using( DbConnection dbConnection = GetDatabaseConnection() ) {   
    doWork();
}

FWIW、GetDatabaseConnection について特別なことは何もありません。MSSQL Server 2000 を実行しているデータベースとの接続を確立します。実際には、次のように表示されます。

DbConnection GetDatabaseConnection() {
    return GetConnection(MyConnectionString);
}

DbConnection GetConnection(String connectionString)
{
  try {
      SqlConnection dbConnection = new SqlConnection(connectionString);
      dbConnection.Open();
      return dbConnection;
  } catch( InvalidOperationException ex ) {
      handleError(ex);
      throw;
  } catch( DbException ex ) {
      handleError(ex);
  }
}

そのため、接続はブロック スコープの最後で破棄されます。しかし、アプリケーションのテストを開始したときに、ちょっとした問題が発生しました。私たちのアプリケーションは非常にバースト性があることがわかりました。つまり、非常におしゃべりになり、しばらく沈黙することがあります。その結果、接続を取得するために複数のスレッドを同時に起動できます。

10 個のスレッドがあるとします。作業のバッチ (作業のバッチを言い換えないでください) が到着し、いくつかのスレッドに分割されます。その後、各スレッドは接続を取得しようとしますが、私は InvalidOperationException に遭遇します。ConnectTimeout を調整しましたが、例外のバーストが発生するまで時間を延ばすだけです。「ワインドアップ」フェーズを過ぎると、アプリケーションは問題ありません。その後、再び静止し、接続が「なくなり」、プロセスが再び開始されます。

LoadBalanceTimeout の調整も試みましたが、引き続き例外が発生します。以前にこの問題を見たことがありますか? どんな考えでも...私は自分のいくつかを捨てます。

  • 一部の接続を継続的に「ホット」に保つ
  • 試行回数まで、接続を再度開くことを試みます
  • 独自の接続プーリングを実装します (車輪の再発明には興味がありません)。

編集:

私が読んだほとんどのフォーラムでは、接続プールのサイズを大きくすることを思いとどまらせていました。デフォルトでは、接続プールには 50 接続の上限があります (これで十分です。増やす必要がある場合は、他の場所で何かが根本的に間違っています)。私が気付いたのは、ConnectTimeout が低い場合に InvalidOperationException が発生することです。接続のスピンアップが長すぎて、保留中の接続がすべてタイムアウトしたかのようです。

MARS は確かにオプションです... InvalidOperationException.Message のテキストは次のとおりです。

タイムアウトになりました。プールから接続を取得する前に、タイムアウト期間が経過しました。これは、プールされたすべての接続が使用中で、最大プール サイズに達したために発生した可能性があります。

4

4 に答える 4

2

MSDN から ( http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx ):

SqlConnection オブジェクトが要求されると、使用可能な接続が使用可能な場合にプールから取得されます。接続を使用できるようにするには、接続が未使用であり、一致するトランザクション コンテキストを持っているか、どのトランザクション コンテキストとも関連付けられていない必要があり、サーバーへの有効なリンクが必要です。

接続プーラーは、接続が解放されてプールに戻されるときに接続を再割り当てすることで、接続の要求を満たします。最大プール サイズに達し、使用可能な接続がない場合、要求はキューに入れられます。その後、プーラーは、タイムアウトに達するまで (デフォルトは 15 秒)、すべての接続を再利用しようとします。接続がタイムアウトする前にプーラーが要求を満たすことができない場合、例外がスローされます。

翻訳: トランザクション コンテキストを確認してください... 10 個の接続のプール サイズがあり、10 個の接続が異なるトランザクションの下で作成されている場合は、失敗しています。

切断された接続は、サーバーとの通信を試行した後にのみ検出できることに注意してください。サーバーに接続されていない接続が見つかった場合、その接続は無効としてマークされます。無効な接続は、クローズまたは再利用された場合にのみ、接続プールから削除されます。

消失したサーバーへの接続が存在する場合、接続プーラーが切断された接続を検出して無効としてマークしていなくても、この接続をプールから引き出すことができます。これは、接続がまだ有効であることを確認するオーバーヘッドによって、サーバーへの別のラウンド トリップが発生し、プーラーを使用するメリットがなくなるためです。これが発生すると、接続を最初に使用しようとすると、接続が切断されたことが検出され、例外がスローされます。

翻訳: 接続が接続されていることに本当に依存することはできませんか? この記事では、これを処理する方法を実際には説明していません...

ClearAllPools と ClearPool を使用して、プールを手動でクリアすることもできますが、これはまだ応急処置のように思えて、うんざりします。

この記事では、セキュリティ コンテキストについても説明
しています。sp_setapprole システム ストアド プロシージャを呼び出して SQL Server アプリケーション ロールをアクティブにすると、その接続のセキュリティ コンテキストをリセットできなくなります。ただし、プーリングが有効になっている場合、接続はプールに返され、プールされた接続を再利用するとエラーが発生します。

なぜ接続プーリングを使用するのか疑問に思い始めています...

最後に:
統合されたセキュリティによるプールの断片化
接続は、接続文字列とユーザー ID に従ってプールされます。したがって、Web サイトで基本認証または Windows 認証を使用し、統合されたセキュリティ ログインを使用すると、ユーザーごとに 1 つのプールが取得されます。これにより、1 人のユーザーに対する後続のデータベース要求のパフォーマンスが向上しますが、そのユーザーは、他のユーザーが作成した接続を利用することはできません。また、ユーザーごとに少なくとも 1 つのデータベース サーバーへの接続が発生します。

そのため、Web アプリで統合セキュリティを使用している場合、十分な数のユーザーがあれば、接続プールがいっぱいになる可能性があります。

アプリケーションの詳細を知らなければ、つまずきの原因を突き止めることは困難ですが、これにより、どこを見るべきかについてのアイデアが得られることを願っています。

HTH

于 2008-12-05T20:50:23.410 に答える
0

質問 1: GetDatabaseConnection() メソッドは新しいスレッドをスピンオフしてデータベース接続を生成し、それをメイン スレッドに返しますか? それとも複数のスレッドがメソッドのこの 1 つのインスタンスにアクセスしようとしていますか? それともこのメソッドはプールから接続を取得するだけの共有/静的メソッド?

質問 2: DB サーバーのメーカーとモデルは何ですか? SQLサーバー?オラクル?PostgreSQL?

質問 3: すべての作業を別々の接続で完了する必要がありますか? それとも、すべてを 1 つの接続で実行できる場合、それで十分ですか? SQL Server の場合は、1 つの接続で複数のレコードセットを許可する MARS が役立つかもしれませんが、アプリには適していない可能性があります。

質問 4: 返された例外の詳細は何ですか?

アプリケーション アーキテクチャがどのように機能しているかを明確に把握しようとしているだけです...

(PS「回答」に「回答ではなく、さらに明確にするためのリクエスト」としてフラグを立てる方法を知っている人はいますか...つまり、この「回答」に対して)

于 2008-12-05T05:29:36.377 に答える
0

「最大プールサイズ」をより高く設定してみてください。また、接続で明示的に「Close」を呼び出してみることもできます。

于 2008-12-05T04:58:30.697 に答える
0

MSDN によると、データ ソースまたはサーバーを指定していない場合、または接続が既に開いている場合、SqlConnection.Open によって InvalidOperationException がスローされます。

「doWork」メソッドで SqlConnection.Open への呼び出しがありませんか?

また、GetConnection メソッドのコードは DbException を飲み込みます。

于 2008-12-05T08:49:54.037 に答える