2014-06-12 53 views
5

我們有一個c#web服務和客戶端,都是在Visual Studio 2008(新項目 - > ASP.Net Web服務應用程序)中創建的。服務託管在Windows Server 2012 R2,IIS 8.5上。winsock資源不足

當客戶端將數據發送到我們的服務時,我們將其轉發給第三方服務,將結果保存到數據庫並將其返回給客戶端。

問題在於,在極少數情況下,當我們的服務處於沉重負載(每秒很多請求)時,它開始拋出'可用於完成套接字連接啓動的不足的winsock資源'。

我們發現我們的Web服務正在打開許多到第三方服務的TCP連接,並將它們保持在TIME_WAIT狀態。當這樣的連接數量達到很高的數量(大約17000)時,整個服務器就失去了建立新連接的能力。從遠程桌面到互聯網瀏覽器的所有內容停止工作。這會持續幾分鐘,然後,當Windows開始關閉這些連接時,它會正常恢復。

對於與第三方服務的通信,我們的服務在其整個生命週期中僅使用一個SoapClient實例。它在初始化時創建,並且永遠不會關閉或銷燬;新的實例永遠不會被創建。

BLIND.BLINDSoapClient client = new BLIND.BLINDSoapClient(base.binding, base.address); 

當數據發送到第三方服務,我們簡單地調用它的Web方法,並把它像沒有關閉,出售或做任何清理:

BLIND.Answer answer = client.Search(...); 
..save to database 
return answer; 

有什麼我們可以做些什麼來避免time_wait連接的這種構建?

有更好的方法來管理SoapClient(s)嗎?我們是否應該爲每個請求打開一個新的soap客戶端並手動關閉它們?

如果是相關的,這裏是如何我們結合設置:

 binding = new BasicHttpBinding(); 
     binding.Name = "SLTDSoap"; 
     binding.CloseTimeout = TimeSpan.FromSeconds(Timeout); 
     binding.OpenTimeout = TimeSpan.FromSeconds(Timeout); 
     binding.ReceiveTimeout = TimeSpan.FromSeconds(Timeout); 
     binding.SendTimeout = TimeSpan.FromSeconds(Timeout); 
     binding.AllowCookies = false; 
     binding.BypassProxyOnLocal = false; 
     binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard; 
     binding.MaxBufferSize = 65536; 
     binding.MaxBufferPoolSize = 524288; 
     binding.MessageEncoding = WSMessageEncoding.Text; 
     binding.TextEncoding = System.Text.Encoding.UTF8; 
     binding.TransferMode = TransferMode.Buffered; 
     binding.UseDefaultWebProxy = true; 

     binding.ReaderQuotas.MaxDepth = 32; 
     binding.ReaderQuotas.MaxStringContentLength = 8192; 
     binding.ReaderQuotas.MaxArrayLength = 16384; 
     binding.ReaderQuotas.MaxBytesPerRead = 4096; 
     binding.ReaderQuotas.MaxNameTableCharCount = 16384; 

     binding.Security.Mode = (_url.StartsWith("https:")) ? BasicHttpSecurityMode.Transport : BasicHttpSecurityMode.None; 
     binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None; 
     binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None; 
     binding.Security.Transport.Realm = ""; 
     binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName; 
     binding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default; 

System.Net.ServicePointManager.DefaultConnectionLimit = 500; 

謝謝!

+0

當我們添加對第三方Web服務的引用時,它是由visual studio創建的類。右鍵單擊服務引用 - >添加服務參考 – dbrckovi

回答

4

我想我們可能已經解決了'winsock資源不足'的問題。

我們已經設置以下注冊表值: HKEY_LOCAL_MACHINE \系統\ CurrentControlSet \服務\ TCPIP \參數\ MaxUserPort的= 60000 HKEY_LOCAL_MACHINE \系統\ CurrentControlSet \服務\ TCPIP \參數\ TcpTimedWaitDelay的= 30

我們最大在峯值時間,生產環境的預期負載是每秒150個請求。這意味着我們將在30秒內創建4500個連接,然後Windows開始釋放它們。 這遠低於60000,應該確保這個問題不會再發生。

我們在3天內以這些設置每秒以150次請求的速度運行系統,問題沒有發生。

0

根據您的推薦BLIND.BLINDSoapClient繼承System.ServiceModel.ClientBase。這個類是IDisposable,這意味着你應該總是在你完成它的時候處理它(在調用Close的背景上 - 它關閉了後臺的通信對象)。

即:

using(var client = new BLIND.BLINDSoapClient(base.binding, base.address)) { 
    // enjoy client 
} 

最終有可能會有一些限制,可以把你的服務器了。您可以:

  1. 在允許你的網站/ Web服務在IIS的請求數量設置限制 - 見http://www.iis.net/configreference/system.applicationhost/sites/sitedefaults/limits,重負載下你調用WebService的,然後偶爾會失敗 - 但在客戶端
  2. 從移動您的Web服務(一個盒子充當負載平衡器,根據當前負載將請求委託給多個盒子)
  3. 將您的webservice移到雲 - 像Amazon或Azure(同樣是2。,只有你不必關心負載平衡器)
+0

我們不能配置BLIND.BLINDSoapClient,因爲我們使用相同的對象與第三方服務進行所有通信。如果我處理它,下一個請求將失敗,因爲客戶端將被關閉。在這種情況下,我們必須爲每個請求創建這個類的新實例。這是一個更好的做法嗎? – dbrckovi

+0

作爲一個方面說明,我們計劃在某個時候將服務轉移到雲端,但我們現在的首要任務是消除可能由不良設計造成的所有問題。 – dbrckovi

+0

@ user3733031 - 最好在您需要時創建新實例,並在完成後立即處理它。否則,連接在整個Web請求期間保持打開狀態,而不是在需要時打開。 –

相關問題