2013-02-12 31 views
6

我有一個相當簡單的WCF Web服務,託管在IIS Express(最終是完整的IIS),使用.Net 3.5。服務方法相當無趣。服務器500:太多待處理的安全對話

[ServiceContract] 
public class MySvc 
{ 
    [OperationContract] 
    public Stuff MyMethod(string input) 
    { 
     Stuff result = DoSomething(); 
     return result; 
    } 
} 

服務配置也相當通用:

<system.serviceModel> 
    <services> 
     <service behaviorConfiguration="MySvcBehavior" name="MySvc"> 
      <endpoint address="" binding="wsHttpBinding" contract="MySvc"> 
       <identity> 
        <dns value="localhost"/> 
       </identity> 
      </endpoint> 
      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
      <behavior name="MySvcBehavior"> 
       <serviceMetadata httpGetEnabled="true"/> 
       <serviceDebug includeExceptionDetailInFaults="false"/> 
      </behavior> 
     </serviceBehaviors> 
    </behaviors> 
</system.serviceModel> 

該服務由一個代碼隱藏在ASPX應用消耗。有一個服務參考,導致一些同樣無趣的代碼。

MySvcClient svc = new MySvcClient(); 
Stuff result = svc.MyMethod("foo"); 

只要它是一次一個請求,一切正常,客戶端代碼得到預期的結果。好極了。

問題出現在我做一些非常原始的壓力測試時。我在瀏覽器中加載客戶端ASPX頁面,然後按住F5鍵。看到IIS Express窗口,首先結果返回爲狀態200,但幾分鐘後我開始看到狀態500.此時,服務將只響應狀態500,直到我重新啓動IIS Express。 (基於等待大約10分鐘)

在客戶端代碼中設置斷點,我看到完整的返回消息是「服務器上的掛起安全對話太多,請稍後再試。

在服務器代碼中設置一個斷點,我發現我的代碼甚至沒有被調用。所以它在通話和我的代碼的實際開始之間的某處失敗。

我的在線搜索並不十分看好,主要是導致相同suggestion of writing a custom binding以覆蓋maxPendingSessions財產,開始由絲線「有人告訴我,有一個[無名]配置文件設置」,然後導致聲稱微軟已經承認這是一個錯誤。

有關maxPendingSessions屬性的鏈接確實提到了超時時間爲兩分鐘的128個連接的限制,我當然可以看到我的測試方法將會中斷某些連接。這是一個公認的糟糕的測試方法的預期結果嗎?或者可以在配置中完成某些操作來改善這一點?

+2

您是否使用'using'語句?連接將保持打開狀態直至處理完畢。除非有'use'語句,否則連接的清除由垃圾收集器決定。 – Caramiriel 2013-03-14 08:57:38

+0

這確實是我的客戶端代碼的問題。但狀態500消息意味着在服務器端的一些事情是不高興的。 – ThatBlairGuy 2013-03-19 20:52:30

回答

4

聽起來就像你有一個在服務器上的開放式連接 - 由於客戶端不使用「使用」的連接。

+0

我不能與這種說法爭辯。 :-)但是由於我不能強迫客戶(除我自己以外)寫得很好,我該如何最好地防範這個問題呢? – ThatBlairGuy 2013-03-20 17:36:16

+0

不幸的是,它基本上(無意)是DOS攻擊(拒絕服務),防止它的唯一方法是在一段時間不活動之後斷開連接。在你的測試案例中,我懷疑這會有所幫助,除非你真的可以將超時設置爲幾秒鐘。 – 2013-03-21 22:14:22

+0

這也是我所得到的結論。 – ThatBlairGuy 2013-03-22 21:30:00

0

與目標服務器的連接太多。有一些方法可以以適當的方式關閉連接。已經提到過,圍繞WCF代理總是應該有一個using聲明。

除此之外,還有(是?)一個錯誤,需要您在打開代理時發出請求。在創建代理時,它給代理大約兩分鐘的時間向服務器發出請求。如果是這樣,它會使計時器無效,從而允許清理代理。如果沒有發出請求,代理在實際關閉連接之前仍然等待超時。這次可能不是這種情況,但爲了完整而添加。

解決此問題的一種方法是利用(ASP.NET)緩存。 System.Web.Caching.Cache是一個很好的候選人。它允許您緩存給定(最終滑動)時間段的結果。通過這種方式,每2分鐘只有一個請求正在進行。這使得網站/ web服務非常具有可擴展性。例如,如果每分鐘有1000個請求,則只有一個連接用於相同的服務調用。

另一種方式來做到這一點,如果請求是昂貴的,不值得等待,以提前做出請求和緩存響應(ALA的cron,任務調度或乾脆另一個線程)。這將允許頁面快速檢索。

除此之外,服務器應該配置正確。從一個客戶端不需要打開128個併發連接。嘗試限制這個,每個客戶端說8個連接。這允許同時處理多個客戶端。也嘗試設置一個體面的超時。等待5分鐘讓客戶端關閉連接,並不會真正提高吞吐量。

也請考慮asynchronous handling of messages。它使用服務必須等待I/O處理額外連接的時間。我看不到WCF服務的功能,所以這可能不相關。

+0

同意,這些都是客戶的良好做法。我需要的是一種**服務**的方式來防禦寫得不好的客戶。 – ThatBlairGuy 2013-03-22 21:27:22

0

對那些建議using語句:你不應該使用using語句關閉客戶端。

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

相反,關閉客戶端,則應該使用下面的代碼片段:如果您不想緩存明確的例外

或只是一個香草抓。有時你會想要捕獲明確的異常,因爲如果通信對象沒有出現故障,你可以重試你的操作,從而最大限度地利用資源。

對於您在服務器上發出的掛起的對話問題,一旦正確關閉了您的客戶端,這種情況就不那麼常見了,但是如果您的服務器端代碼有長時間運行的操作並且客戶端正在排隊等待,您仍然可以看到它。在這種情況下,要增加MaxPendingChannels的值,您必須在客戶端和接收端配置文件中使用自定義綁定,或者在啓動服務之前以編程方式修改接收端的綁定。如果您使用的是.NET 3.5,則MaxPendingChannels的默認值實際上是4。據稱.NET 3.0的值爲128。我認爲兩者都很低。

請參閱http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/745b95d2-1480-4618-89f5-1339d6ee228d

相關問題