閱讀285 返回首頁    go windows


WCF 4.0一個鮮為人知的改變[兼書名征集]

本篇文章介紹可以算是WCF 4.0基於限流(Throttling)的新特性,是在修訂《WCF技術剖析(卷1)》的時候編寫演示實例的時候發現的。這個特性沒有出現在官方文檔上麵,至少在MSDN上的相關介紹依然是錯誤的。

WCF是一個基於多線程的消息監聽、接收和處理框架體係,能夠同時應付來自相同或者不同客戶端的服務調用請求,並提供完善的同步機製確保狀態的一致性。一方麵,我們期望WCF服務端能夠處理盡可能多的並發請求,但是資源的有限性決定了並發量有一個最大值。如果WCF不控製進入消息處理係統的並發量,試圖處理所有抵達的並發請求,一旦超過了這個臨界值,整個服務端將會由於資源耗盡而崩潰。

所以,我們需要在WCF的消息接收係統和消息處理係統之間設置一道道屏障,將流入消息處理係統的請求控製到一個最佳的範圍,以實現對現有資源的有效利用,從而達到確保服務的可用性和提高整體吞吐量的目的。WCF的流向限製(Throttling)為你設置了這些屏障,你可以根據現有的軟硬件環境對該閘門準入的並發流量進行動態的配置。

WCF對限流的控製是通過一個服務行為(Service Behavior)實現的,該服務行為類型名稱為ServiceThrottlingBehavior,定義在System.ServiceModel.Description命名空間下。ServiceThrottlingBehavior定了三個整型的屬性:MaxConcurrentCallsMaxConcurrentInstancesMaxConcurrentSessions。它們分別代表流量控製的三個閥值,簡單地說,我們所說的限流就是通過設置這三個值控製能夠處理的並發量。

基於.NET Framework 4.0的MSDN對上述三個限流閥值是這樣介紹的:

通過ServiceThrottlingBehaviorMaxConcurrentSessions屬性表示的最大並發會話數默認為10,果真如此嗎?我們不妨通過一個簡單的實例來驗證。照理以計算服務為例,下麵是契約接口和服務類型的定義。

   1: [ServiceContract(Namespace ="https://www.artech.com/")]
   2: public interface ICalculator
   3: {
   4:     [OperationContract]
   5:     double Add(double x, double y);
   6: }
   7:  
   8: public class CalculatorService : ICalculator
   9: {      
  10:     public double Add(double x, double y)
  11:     {
  12:         return x + y;
  13:     }
  14: }

我們采用控製台程序對CalculatorService進行寄宿,如下所示的是采用的配置:

   1: <configuration>
   2:   <system.serviceModel>
   3:     <services>
   4:       <service name="Artech.WcfServices.Service.CalculatorService">
   5:         <endpoint  address="https://127.0.0.1:3721/calculatorservice"
   6:                    binding="ws2007HttpBinding"
   7:                    contract="Artech.WcfServices.Service.Interface.ICalculator"/>
   8:       </service>
   9:     </services>
  10:   </system.serviceModel>
  11: </configuration>

從上麵的配置中我們知道寄宿的服務具有一個唯一的基於WS2007HttpBinding(支持會話)的終結點。客戶端采用相應的配置並通過如下的代碼進行服務的調用。

   1: using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorservice"))
   2: {
   3:     bool stop = false;
   4:     for (int i = 0; i < 1000 && !stop; i++)
   5:     {
   6:         ICalculator calcultor = channelFactory.CreateChannel();
   7:         try
   8:         {
   9:             calcultor.Add(1, 2);
  10:             Console.WriteLine("第{0}個服務代理調用成功!", i + 1);
  11:         }
  12:         catch (Exception ex)
  13:         {
  14:             Console.WriteLine("出現異常:{0}", ex.Message);
  15:             stop = true;
  16:         }
  17:     }
  18:    }

在上麵這段用於進行服務調用的代碼中,我們通過基於客戶端終結點配置名稱創建的ChannelFactory<TChannel>對象創建了1000個服務代理進行用其進行1000次服務調用。當上麵這個實例運行的時候,客戶端控製台將會出現如下的輸出結果。實例程序清晰地反映了這樣的事實:雖然我們通過不同的服務代理對象進行了1000次服務調用,但是隻有前麵兩百次是成功的。如果默認的最大並發會話數是10的話,隻有前麵10次服務調用會成功。

   1: 第1個服務代理調用成功!
   2: 第2個服務代理調用成功!
   3:    ...
   4: 第199個服務代理調用成功!
   5: 第200個服務代理調用成功!
   6: 出現異常:請求通道在等待 00:00:59.9844000 以後答複時超時。增加傳遞給請求調用的超時值,或者增加綁定上的 SendTimeout 值。分配給此操作的時間可能已經是更長超時的一部分。

通過上麵演示的實例,我們發現默認情況下允許200次並發會話,那麼MaxConcurrentSessions的默認值不是10,而是200嗎?由於三個限流屬性值是通過配置的方式進行指定的,所以要了解它們的默認值,隻需要了解對應的配置元素類型的定義即可。下麵是ServiceThrottlingBehavior對應的配置元素ServiceThrottlingElement 的定義。

   1: public sealed class ServiceThrottlingElement : BehaviorExtensionElement
   2: {
   3:      //...
   4:     [ConfigurationProperty("maxConcurrentCalls", DefaultValue=0x10)]
   5:     public int MaxConcurrentCalls { get; set; }
   6:  
   7:     [ConfigurationProperty("maxConcurrentInstances", DefaultValue=0x74)]
   8:     public int MaxConcurrentInstances { get; set; }
   9:  
  10:     [ConfigurationProperty("maxConcurrentSessions", DefaultValue=100)]
  11:     public int MaxConcurrentSessions { get; set; }
  12: }
  13:  

從應用在三個配置屬性上ConfigurationPropertyAttribute特性可以看出,MaxConcurrentCalls、MaxConcurrentInstances 和MaxConcurrentSessions 的默認值為16、116和100,而不是MSDN所說的16、26和10。

既然MaxConcurrentSessions的默認值為100,那麼我們的實例為什麼會有200次成功的並發訪問呢?原因很簡單:這三個限流閥值都是針對單個處理器的,由於運行機器采用雙核處理器,自然就是200。


前後花了一年多的時間,終於將《WCF技術剖析(卷2)》完成了,不過在對《卷1》進行修訂的時候又對現有的內容作了較大的改動。這不僅僅添加了許多新的內容,還大刀闊斧的刪除和修改了現有的一些內容。正是由於改動較大,編輯建議換個名字並出上下卷。由於我個人還未給新書想到一個好的名字,希望通過本貼進行征名。你提供的書名一旦采用,在新書出版時我個人會贈送本書的上下兩冊。

[]
[]


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-26 14:04:55

  上一篇:go  Java和Spring的跨版本升級
  下一篇:go  像TransactionScope一樣使用DbTransaction