2009-06-11 62 views
92

我們有一個應用程序具有在IIS7上運行的WCF服務(* .svc)以及查詢該服務的各種客戶端。該服務器正在運行Win 2008 Server。客戶端運行Windows 2008 Server或Windows 2003服務器。我收到以下例外,我已經看到它可能實際上與大量潛在的WCF問題有關。WCF超時異常詳細調查

System.TimeoutException: The request channel timed out while waiting for a reply after 00:00:59.9320000. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout. ---> System.TimeoutException: The HTTP request to 'http://www.domain.com/WebServices/myservice.svc/gzip' has exceeded the allotted timeout of 00:01:00. The time allotted to this operation may have been a portion of a longer timeout. 

我把超時時間增加到30分鐘,錯誤仍然發生。這告訴我其他的事情正在發揮作用,因爲數據量從未上傳或下載需要30分鐘。

錯誤來了又去。目前,它更頻繁。如果我有3個客戶端同時運行或100個,似乎並不重要,但它仍會偶爾發生。大多數時候,沒有超時,但我仍然每小時得到幾個。錯誤來自任何被調用的方法。其中一種方法沒有參數並返回一點數據。另一個需要大量的數據作爲參數,但是異步執行。錯誤總是來自客戶端,並且從不在堆棧跟蹤中引用服務器上的任何代碼。它總是結束與:

at System.Net.HttpWebRequest.GetResponse() 
    at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) 

在服務器上: 我試過(和目前有)以下的綁定設置:

maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" 

它似乎並沒有產生影響。

我試過(和目前有)以下限制設置:

<serviceThrottling maxConcurrentCalls="1500" maxConcurrentInstances="1500" maxConcurrentSessions="1500"/> 

它似乎並沒有產生影響。

我目前有WCF服務的以下設置。

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)] 

我跑ConcurrencyMode.Multiple一段時間,錯誤仍然發生。

我試過重新啓動IIS,重新啓動我的底層SQL Server,重新啓動計算機。所有這些似乎都沒有影響。

我試過禁用Windows防火牆。它似乎沒有影響。

在客戶端,我有以下設置:

maxReceivedMessageSize="2147483647" 

<system.net> 
    <connectionManagement> 
    <add address="*" maxconnection="16"/> 
</connectionManagement> 
</system.net> 

我的客戶端關閉其連接:

var client = new MyClient(); 

try 
{ 
    return client.GetConfigurationOptions(); 
} 
finally 
{ 
    client.Close(); 
} 

我已經改變了註冊表設置,以允許更傳出連接:

MaxConnectionsPerServer=24, MaxConnectionsPer1_0Server=32. 

我現在剛剛嘗試過SvcTraceViewer.exe。我設法在客戶端捕捉到一個例外。我看到它的持續時間是1分鐘。看看服務器端跟蹤,我可以看到服務器不知道這個異常。我能看到的最長持續時間是10秒。

我看過服務器上使用exec sp_who的活動數據庫連接。我只有幾個(2-3)。我使用TCPview從一個客戶端查看了TCP連接。它通常是2-3左右,我已經看到了5或6.

簡單地說,我很難過。我嘗試了所有我能找到的東西,並且必須錯過WCF專家能夠看到的非常簡單的東西。我的直覺是,在服務器實際接收到消息之前和/或某些東西在服務器級別排隊消息並且從不讓他們處理消息之前,某些東西阻止了我的客戶端在低級別(TCP)。

如果你有任何性能計數器,我應該看看,請讓我知道。 (請指出哪些值是不好的,因爲其中一些計數器很難降解)。另外,如何記錄WCF消息大小?最後,有沒有什麼工具可以讓我測試我的客戶端和服務器之間可以建立多少個連接(獨立於我的應用程序)

感謝您的時間!

額外的信息添加6月20日:

我的WCF應用程序做類似如下的東西。

while (true) 
{ 
    Step1GetConfigurationSettingsFromServerViaWCF(); // can change between calls 
    Step2GetWorkUnitFromServerViaWCF(); 
    DoWorkLocally(); // takes 5-15minutes. 
    Step3SendBackResultsToServerViaWCF(); 
} 

使用Wireshark的,我沒有看到,發生錯誤時,我有一個5個TCP重發之後的TCP重置以後。我的猜測是RST來自WCF,會導致連接中斷。我得到的例外報告是從Step3超時。

我通過查看tcp流「tcp.stream eq 192」發現了這一點。然後我將過濾器擴展爲「tcp.stream eq 192和http和http.request.method eq POST」,並在此流中看到了6個POST。這看起來很奇怪,所以我檢查了另一個流,例如tcp.stream eq 100.我有三個POST,這看起來更正常一些,因爲我正在進行三個調用。但是,在每次WCF調用之後,我都會關閉連接,因此我希望每個流都有一個調用(但我對TCP的瞭解不多)。

調查了一會兒,我將http數據包加載到磁盤,看看這六個調用在哪裏。

1) Step3 
2) Step1 
3) Step2 
4) Step3 - corrupted 
5) Step1 
6) Step2 

我的猜測是兩個併發客戶端使用相同的連接,這就是爲什麼我看到重複。但是,我仍然有一些我無法理解的問題:

a)爲什麼數據包被破壞?隨機網絡僥倖 - 也許?使用此示例代碼對負載進行gzip壓縮:http://msdn.microsoft.com/en-us/library/ms751458.aspx - 同時使用時,代碼有時可能會出現一次錯誤?我應該測試沒有gzip庫。

b)爲什麼我會看到步驟1 &步驟2在損壞的操作超時後運行?在我看來,這些操作應該不會發生。也許我不是在看正確的流,因爲我對TCP的理解是有缺陷的。我有其他的流同時發生。我應該調查其他流 - 快速瀏覽流190-194顯示Step3 POST具有合適的有效負載數據(未損壞)。推動我再次查看gzip庫。

+0

Jason - 您是否曾經解決過這個問題?它是DefaultConnectionLimit設置嗎? – SFun28 2011-01-26 15:15:34

+2

@JasonKealey - 與許多其他問題不同,在發佈問題之前,不能指責你不要自己嘗試:)我喜歡你的問題非常詳細,並且包含所有重要細節。你描述的症狀看起來非常像我的,所以我希望解決方案是一樣的:) – 2013-04-11 09:26:00

回答

46

如果您使用的是.NET客戶端,那麼你可能不會設置

//This says how many outgoing connection you can make to a single endpoint. Default Value is 2 
System.Net.ServicePointManager.DefaultConnectionLimit = 200; 

這裏是原來的問題和回答WCF Service Throttling

更新

這個配置進去的.Net客戶端應用程序可能正在啓動,或者在開始測試之前。

而且你可以把它在app.config文件,以及像下面

<system.net> 
    <connectionManagement> 
     <add maxconnection = "200" address ="*" /> 
    </connectionManagement> 
    </system.net> 
2

來自:http://www.codeproject.com/KB/WCF/WCF_Operation_Timeout_.aspx

爲了避免這種超時錯誤,我們需要 到配置OperationTimeout 屬性代理的WCF客戶端 代碼。這種配置是 新的東西不像其他配置 作爲發送超時,接收超時等, ,我在 文章的早期討論。要設置此操作超時 屬性配置,我們必須 將我們的代理投入到 WCF客戶端應用程序的IContextChannel中,然後調用 的操作合約方法。

+0

我試過這個。無論我提出的超時,它仍然超時,但這是沒有意義的,因爲操作時間並不長,因爲在此期間執行相同查詢的所有其他客戶端都有效。 – 2009-06-11 16:16:04

+0

我的測試證明了OperationTimeout簡單地覆蓋了配置中的ReceiveTimeout。因此,這是沒有用的。 – dudeNumber4 2012-01-11 14:04:43

0

您是否嘗試過使用clientVia來查看發送的消息,使用SOAP toolkit或類似的東西?這可能有助於查看錯誤是來自客戶端本身還是來自其他地方。

+0

您是否知道任何比廢棄的SOAP工具包更新的工具,這些工具可以使我更容易在WCF調用中記錄此信息? – 2009-06-15 14:21:30

+0

你可以試試soapUI http://www.soapui.org/。 – Philippe 2009-06-16 08:06:28

+0

*** SOAP Toolkit *** * *``棄用'* – Kiquenet 2015-11-25 15:20:45

0

我不是WCF專家,但我想知道如果您沒有在IIS上運行DDOS保護。 我從經驗中知道,如果您在某個點運行一組從同一個客戶端到服務器的同時連接,服務器因爲懷疑DDOS攻擊而停止響應這些呼叫。它也將持續打開連接,直到它們超時,以便在攻擊中減慢客戶端速度。

但是,來自不同機器/ IP的多個連接應該不成問題。

還有在這個MSDN發佈更多信息:

http://msdn.microsoft.com/en-us/library/bb463275.aspx

退房的MaxConcurrentSession sproperty。

+0

我覺得這是發生了什麼,從我看到的一切,但我有(在服務器上): 會有任何性能監視器或IIS日誌,我可以監視,看看是否發生這種情況? – 2009-06-16 11:40:14

0

你檢查過WCF的痕跡嗎? WCF傾向於吞下異常,並僅返回最後一個異常,這是您所得到的超時,因爲結束點沒有返回任何有意義的結果。

3

如果您還沒有嘗試過 - 在try/finally塊中封裝您的服務器端WCF操作,並添加日誌記錄以確保它們實際返回。

如果那些顯示操作正在完成,那麼我的下一步將是進入較低級別,並查看實際的傳輸層。

Wireshark或其他類似的數據包捕獲工具在這一點上可能相當有幫助。我假設這是通過HTTP在標準端口80上運行。

在客戶端上運行Wireshark。在開始捕獲的選項中,將捕獲過濾器設置爲tcp http and host service.example.com - 這將減少不相關的流量。

如果可以,請修改您的客戶端以通知您確切的呼叫開始時間以及發生超時的時間。或者只是密切監視它。

當您遇到錯誤時,您可以瀏覽Wireshark日誌以查找呼叫的開始。右鍵單擊第一個包含客戶端調用的數據包(應該是GET /service.svc或POST /service.svc),然後選擇Follow TCP Stream。

Wireshark將解碼整個HTTP會話,因此您可以確保WCF實際上發回響應。

2

我有一個非常類似的問題。過去,這與序列化問題有關。如果你仍然有這個問題,你可以驗證你可以正確地序列化你正在返回的對象。特別是,如果你使用的是有關係的LINQ到SQL對象,還有如果你把一個子對象的父對象和標記是反向引用的數據成員上一回參考已知序列化的問題。

您可以通過編寫序列化和反序列化使用DataContractSerializer的在服務器端的對象和任何序列化方法您的客戶端使用一個控制檯應用程序驗證序列化。例如,在我們當前的應用程序中,我們同時擁有WPF和Compact Framework客戶端。我編寫了一個控制檯應用程序來驗證我可以使用DataContractSerializer進行序列化,並使用XmlDesserializer進行反序列化。你可以試試。

另外,如果你正在返回擁有子集合LINQ到SQL對象,你可以嘗試,以確保您已即時加載它們在服務器端。有時候,由於延遲加載,返回的對象沒有被填充,並且可能會導致您看到多次將請求發送到服務方法的行爲。

如果你已經解決了這個問題,我很想聽聽怎麼樣,因爲我堅持了這一點。我已經證實我的問題不是序列化,所以我不知所措。

更新:我不知道這是否會幫助你,但任何服務跟蹤查看器工具只是解決了我的問題後非常相似的經歷到你的5天。通過設置跟蹤,然後查看原始XML,我發現導致序列化問題的異常。它與Linq-to-SQL對象有關,偶爾有更多的子對象可能被成功序列化。添加以下到您的web.config文件應該啓用跟蹤:

<sharedListeners> 
    <add name="sharedListener" 
     type="System.Diagnostics.XmlWriterTraceListener" 
     initializeData="c:\Temp\servicetrace.svclog" /> 
    </sharedListeners> 
    <sources> 
    <source name="System.ServiceModel" switchValue="Verbose, ActivityTracing" > 
     <listeners> 
     <add name="sharedListener" /> 
     </listeners> 
    </source> 
    <source name="System.ServiceModel.MessageLogging" switchValue="Verbose"> 
     <listeners> 
     <add name="sharedListener" /> 
     </listeners> 
    </source> 
    </sources> 

產生的文件可以與服務跟蹤查看工具或打開只在IE中檢查結果。

0

您還將收到此錯誤如果您將對象傳遞迴包含類型爲enum的屬性的客戶端,該屬性未默認設置,並且該枚舉不具有映射爲0的值。即enum MyEnum{ a=1, b=2};

2

你關閉在請求之間的WCF服務的連接?如果你不這樣做,你會看到確切的超時(最終)。

2

我剛剛解決了這個問題。我發現App.config文件中的節點出現錯誤。

<client> 
<endpoint name="WCF_QtrwiseSalesService" binding="wsHttpBinding" bindingConfiguration="ws" address="http://cntgbs1131:9005/MyService/TGE.ISupplierClientManager" contract="*"> 
</endpoint> 
</client> 

<bindings> 
    <wsHttpBinding> 
     <binding name="ws" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text"> 
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/> 
      <**security mode="None">** 
       <transport clientCredentialType="None"></transport> 
      </security> 
     </binding> 
    </wsHttpBinding> 
</bindings> 

確認在節點<security>你的配置,屬性「模式」值爲「無」。如果您的值爲「Transport」,則會發生錯誤。

0

看起來像這個異常消息是相當通用的,可以由於各種原因接收。我們在Windows 8.1機器上部署客戶端時遇到了這個問題。我們的WCF客戶端在Windows服務中運行並不斷輪詢WCF服務。 Windows服務在非管理員用戶下運行。通過在WCF配置中將clientCredentialType設置爲「Windows」來解決此問題,以允許身份驗證通過,如下所示:

 <security mode="None"> 
     <transport clientCredentialType="Windows" proxyCredentialType="None" 
      realm="" /> 
     <message clientCredentialType="UserName" algorithmSuite="Default" /> 
     </security>