web-dev-qa-db-ja.com

マルチスレッドWindowsサービスでの複数の同時SQL接続タイムアウト

VS 2010(.NET 4.0)で開発したマルチスレッドWindowsサービスがあります。このサービスには、数スレッドから数十スレッドのスレッドがあり、それぞれがインターネット経由で低速サーバーからデータを取得し、ローカルデータベースを使用してこれを記録します。データ(したがって、プロセスはインターネットにバインドされ、LANまたはCPUにバインドされません)。

定期的に、複数のスレッドから同時に次のエラーのフラッド/フラリー/バーストが発生します。

System.Data.SqlClient.SqlException(0x80131904):タイムアウトが期限切れになりました。操作が完了する前にタイムアウト期間が経過したか、サーバーが応答していません。

このエラーのコールスタックは通常、次のとおりです。

system.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)で

system.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)で

system.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outsideConnection、DbConnectionFactory connectionFactory)で

system.Data.SqlClient.SqlConnection.Open()で

接続文字列に接続タイムアウトを指定していません。このデータベースで動作している他のアプリケーションとプロセスがあります。誰かがこの種の行動に出くわしたことがありますか?もしそうなら、それを防ぐために何が行われましたか?

私のデータアクセス層で最も一般的に呼ばれるメソッドは次のようになり、他のすべてのDALメソッドは同じアプローチに従います。

using (SqlConnection con = new SqlConnection(GetConnectionString()))
using (SqlCommand cmd = new SqlCommand("AddGdsMonitorLogEntry", con))
{
    cmd.CommandType = CommandType.StoredProcedure;

    /* setting cmd.Parameters [snipped] */

    // We have been getting some timeouts writing to the log; wait a little longer than the default.
    cmd.CommandTimeout *= 4;

    con.Open();

    cmd.ExecuteNonQuery();
}

どうもありがとう!

[〜#〜]編集[〜#〜]

ミラーリングされた環境で発生するこれについてのコメントを考えると、問題のデータベースがミラーリングされていることは確かに言及する必要があります。 SSMSでは、「自動フェイルオーバーなしの高安全性(同期)」モードで「プリンシパル、同期」としてマークされています。

2011年5月26日編集

SQL Serverのログには、問題を示すものが何も表示されません。 (そのサーバー上のWindowsイベントビューアーにアクセスできませんが、誰かに私を探すように依頼しました。)

25
ALEXintlsos

MSDNブログの投稿 今日作成されたばかりです(Googleに感謝します!)

Microsoftは、これがADO.NETの現在のリリースの問題であることを確認しています。この問題は、Visual Studio2011に付属するADO.NETバージョンで修正されます。

それまでの間、次の回避策を使用することをお勧めします。

  1. 接続文字列のタイムアウトを150秒に増やします。これにより、最初の試行で接続するのに十分な時間が与えられます(150 * .08 = 12秒)

  2. 接続文字列にMinPoolSize = 20を追加します。これにより、プール内に常に最低20の接続が維持され、新しい接続を作成する可能性が低くなるため、このエラーの可能性が低くなります。

  3. ネットワークパフォーマンスを向上させます。 NICドライバーを最新のファームウェアバージョンに更新します。NICカードが特定のScalableNetworking Pack設定と互換性がない場合、ネットワーク遅延が発生します。 Windows Vista SP1以降では、受信ウィンドウの自動調整を無効にすることも検討できます。NICチーミングを有効にしている場合は、無効にすることをお勧めします。

投稿自体は興味深い読み物であり、TCP/IP接続の再試行アルゴリズムについて説明しています。そして、「これはミラーリングに関連しているようだ...」と言ったすべての人々への称賛!また、これが「SQL Serverからの応答が遅いため、またはネットワークの遅延が原因」であるというコメントに注意してください。

UGH !!!

投稿してくださった皆様、ありがとうございました。ここで、.NET Framework(またはその他のADO.NETパッチ適用メカニズム)へのパッチを要求する必要があるため、Visual Studio 11を待つ(そして購入する)必要はありません...

15
ALEXintlsos

接続タイムアウトは、コマンドタイムアウトとは異なります。コマンドタイムアウトは、接続が確立されている状況に適用されますが、内部的な理由により、サーバーは必要な時間内に結果を返すことができません。デフォルトのコマンドタイムアウトは30秒です。 http://msdn.Microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx

接続文字列で接続タイムアウトを指定してみてください。デフォルト値は15秒ですが、これが問題の原因である可能性があります。コードで接続タイムアウトを指定することもできます: http://msdn.Microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectiontimeout.aspx

7
Piotr Rodak

私はこれを私たちが持っているこの古いデータベースサーバー(今は10年前に登場)で時々入手します。それが起こったとき、それは何かが接続/クエリでそのことを絶えず叩いているからです。とにかく、私の経験では、コードを最適化し、データベースを最適化し、より強力にすることができれば、データベースサーバーに負荷がかかっている(または接続数が多いなど)ことがわかると思います。データベースサーバーなどはすべて役に立ちます。 Piotrが提案するもう1つの方法は、接続のタイムアウトを増やすことです。私はまだいくつかのものを調べて最適化します(長期的には役立つはずです)。

1
JaCraig

私はこの問題をある程度確実に再現することができました。処理ジョブが要求されると、新しいappdomain/threadで処理を開始するサービスがあります。このスレッドは、10から16のデータベースクエリを同時に実行します。これらのジョブを30個次々に実行すると、ランダムな1つまたは2つのジョブがタイムアウトエラーでクラッシュします。

接続文字列を変更して、Pooling = falseで接続プールをオフにしたところ、エラーが次のように変更されました。接続はParallel.For内で発生しているため、これは集約例外内で3〜4回スローされます。

System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
   at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
   at System.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(Boolean encrypt, Boolean trustServerCert, Boolean& marsCapable)
   at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity)
   at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, SqlConnection owningObject)
   at System.Data.SqlClient.SqlInternalConnectionTds.LoginWithFailover(Boolean useFailoverHost, ServerInfo primaryServerInfo, String failoverHost, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout)
   at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, TimeoutTimer timeout, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance)
   at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance)
   at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at Tps.PowerTools.CoreEngine.V5.DataAccess.DataContext.ExecuteQuery(PtQuery query, ValueStore`1 store, String readerDescription) in C:\SourceCode\Tps.PowerToolsV1\Trunk\Libraries\CoreEngine\CoreEngine.V5\DataAccess\DataContext.cs:line 326
   at Tps.PowerTools.CoreEngine.V5.DataAccess.DataContext.<StockHistoricalData>b__15(PtQuery query) in C:\SourceCode\Tps.PowerToolsV1\Trunk\Libraries\CoreEngine\CoreEngine.V5\DataAccess\DataContext.cs:line 302
   at System.Threading.Tasks.Parallel.<>c__DisplayClass32`2.<PartitionerForEachWorker>b__30()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object )
0
BrandonAGr

リモートサーバーで実行しているクエリを最適化すると、常に役立ちます。各クエリの時間を計り、実行時間の長いクエリを探します。読み取りを行うだけの場合は、SELECTステートメントで (NOLOCK) ヒントを使用します。これは私にとって命の恩人でした。それを読んで、アプリケーションに適切であることを確認してください。リモートデータベースにアクセスできる場合は、 インデックスが断片化されていない であることを確認してください。これにより、クエリの実行が大幅に遅くなります。 SQL保守計画の一部として、索引が再構築/再編成されていることを確認してください。必要に応じて新しいインデックスを追加します。

タイムアウトを延長すると、問題が発生する可能性があります悪化。クエリの実行時間を長くすると、より多くのクエリがタイムアウトする可能性があります。タイムアウトは、サーバーとそれにアクセスする他のクライアントを保護するためにあります。少し増やすことは大したことではありませんが、クエリを長時間実行してサーバーを強制終了することは望ましくありません。

0
nbushnell