2011-05-04 99 views
24

我有一個多線程的Windows服務,我用VS 2010(.NET 4.0)從一個緩慢的服務器開發了可從幾隨時隨地有幾十個線程,每個線程檢索數據通過互聯網,然後使用本地數據庫記錄此數據(因此該過程是Internet連接的,而不是LAN或CPU綁定的)。多個同時SQL連接超時在多線程Windows服務

有一定的規律性,我得到一個洪水/亂舞/同時從多個線程爆了以下錯誤:

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 outerConnection,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中標記爲「Principal,Synchronized」,在「沒有自動故障轉移(同步)的高安全性」模式中。

編輯11年5月26日

我看到什麼在SQL Server日誌來說明任何問題。 (我沒有訪問Windows事件查看器的服務器上,但我問的人找我。)

+0

我也看到完全相同的問題,使用相同的堆棧跟蹤。它連接的數據庫是鏡像的,連接字符串指定了故障轉移夥伴。我一直無法從本地桌面重現相同的問題,打開一堆連接並從不關閉它們會產生不同的異常消息。 – BrandonAGr 2011-05-13 20:05:31

+0

這些鏈接報告類似的問題,但沒有提供解決方案:[1](http://stackoverflow.com/questions/3140738/why-timeout-may-occur-in-sqlconnection-open)[2](http: //blog.brianhartsock.com/2009/09/29/interesting-sql-server-mirroring-problem/)[3](http://social.msdn.microsoft.com/Forums/en/sqldatabasemirroring/thread/918e4a7f -1fc5-4679-958f-4c4f07b6ae76)[4](http://social.msdn.microsoft.com/Forums/en/adodotnetdataproviders/thread/e93fae99-a832-407f-9e80-f7a27b1c6194)[5](http:/ /social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/d3798fe7-fc7f-45aa-87ca-cd365abc4b55) – BrandonAGr 2011-05-13 20:11:36

+0

我認爲問題不在於連接,客戶端或數據庫。但在查詢執行。驗證它們,例如收集統計信息SP /查詢更頻繁地引發異常 – abatishchev 2011-05-15 14:11:45

回答

14

根據MSDN Blog post剛剛創建的今天,以(萬歲谷歌!):

Microsoft已經確認這是在ADO.NET的當前版本中的一個問題。這個問題將在ADO.NET版本,船舶與Visual Studio 2011年

在此期間,我們要求使用以下解決方法:

  1. 增加連接字符串超時150秒。這將給第一次嘗試足夠的時間連接(150 * .08 = 12秒)

  2. 在連接字符串中添加MinPool Size = 20。這將始終保持池中至少20個連接,並且創建新連接的機會將減少,從而減少出現此錯誤的機率。

  3. 提高網絡性能。將您的網卡驅動程序更新到最新的固件版本。當您的NIC卡與某些Scalable Networking Pack設置不兼容時,我們已經看到網絡延遲。如果您使用的是Windows Vista SP1或更高版本,則可能會考慮禁用接收窗口自動調整功能。如果您啓用了網卡綁定,禁用它將是一個不錯的選擇。

的職位本身是一個有趣的閱讀,談論的是TCP/IP連接重試算法。並讚揚所有的人誰說:「嘿,這看起來像它與鏡像......」!並注意關於這個問題的評論:「由於SQL Server響應緩慢或網絡延遲」。

UGH !!!

感謝所有發佈的人。現在我們都必須向.NET Framework(或其他ADO.NET修補機制)尋求補丁,因此我們不必等待(併購買)Visual Studio 11 ...

7

連接超時比命令超時不同的事情。命令超時適用於建立連接時的情況,但由於某些內部原因,服務器無法在所需時間內返回任何結果。默認命令超時是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

+0

我想增加連接超時,但是這個錯誤是*只*發生在連接上,而不是存儲過程執行。命令超時與此無關。但是我的擔心更多的是爲什麼這種情況只是間歇性地發生,爲什麼它會同時影響這麼多嘗試的連接。我在這裏有一個DBA /開發人員,他說這聽起來像是服務器端連接池中可能會有某些事情發生(我不得不承認我不知道有* server *端池這樣的東西)。但是這沒有得到證實。 – ALEXintlsos 2011-05-24 13:28:50

+0

如果服務器連接池出現問題,那麼在SQL Server錯誤日誌中會有一些指示。你能證實這一點嗎? 我認爲,如果網絡速度較慢,所有線程的連接都會因此而受到影響。所有的連接都通過相同的電線。 我們最近有類似的問題 - 我們的應用服務器經歷了間歇性超時。事實證明,服務器之間的路由不正確,網絡性能波動很大。然後我們的應用程序會拋出所有線程的超時異常。 – 2011-05-24 23:01:25

+0

恐怕SQL Server日誌中沒有任何東西。有關如何檢測網絡性能波動的任何建議? – ALEXintlsos 2011-05-26 14:11:07

0

我已經能夠稍微可靠地重現此問題。我有一個服務,當處理作業被請求時,它開始處理一個新的appdomain /線程。該線程將同時執行10到16個數據庫查詢。當我一個接一個地運行這些作業中的30個時,隨機的一個或兩個作業會因超時錯誤而崩潰。

我更改了連接字符串以關閉Pooling = Pooling = false,然後錯誤更改爲以下內容。這被拋出3或4次合計異常中,由於連接內的Parallel.For

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) 
1

我得到這個每一次在這個古老的數據庫服務器上的,而我們(10上來發生現在歲)。當它發生的時候,雖然這是因爲有些東西在不斷地用連接/查詢來錘擊這件事。我的猜測是,你會發現當數據庫服務器發生負載時(或者大量的連接或者這些線上的某些東西)無論如何,根據我的經驗,如果你可以優化代碼,優化數據庫,變得更加強大數據庫服務器等都有所幫助。 Piotr建議你可以做的另一件事是簡單地延長連接的超時時間。我仍然會通過並優化一些東西,雖然(應該從長遠來看有所幫助)。

0

優化您在遠程服務器上執行的查詢將始終有幫助。爲每個查詢計時並查找長時間運行的查詢。如果您只是在讀取數據,請在SELECT語句中使用(NOLOCK)提示。這對我來說是一種拯救生命。只需閱讀它,以確保它適用於您的應用程序。如果您有權訪問遠程數據庫,請確保indexes are not to fragmented。這會導致查詢執行速度下降。確保索引被重建/重組爲SQL維護計劃的一部分。在適當的地方添加新索引。

延長超時可能會使變得更糟。如果讓查詢運行時間更長,則可能會有更多查詢超時。超時是爲了保護服務器和其他客戶端訪問它。將其稍微提升一點並不是什麼大問題,但是您不希望查詢長時間運行而終止服務器。

+0

我認爲如果我在執行命令期間遇到問題,這個答案是恰當的;然而,它發生在連接開放時,所以查詢甚至還沒有開始。 – ALEXintlsos 2011-05-24 13:30:05

+0

「如果你只是在讀取,然後使用(NOLOCK)提示」 - 這不是一般的忠告。 – StingyJack 2016-11-02 13:27:06

+0

@StingyJack這就是爲什麼有這樣的告誡句「只需閱讀它,以確保它在您的應用程序中是適當的。」在我的迴應中。 – nbushnell 2016-11-14 19:53:30