一、流量限制簡介
WCF是一個基於多線程的消息監聽、接收和處理框架體系,能夠同時應付來自相同或者不同客戶端的服務調用請求,並提供完善的同步機制確保狀態的一致性。一方面,我們期望WCF服務端能夠處理儘可能多的併發請求,但是資源的有限性決定了併發量有一個最大值。如果WCF不控制進入消息處理系統的併發量,試圖處理所有抵達的併發請求,一旦超過了這個臨界值,整個服務端將會由於資源耗盡而崩潰。
所以,我們需要在WCF的消息接收系統和消息處理系統之間設置一道道屏障,將流入消息處理系統的請求控制到一個最佳的範圍,以實現對現有資源的有效利用,從而達到確保服務的可用性和提高整體吞吐量的目的。WCF的流向限制(Throttling)爲你設置了這些屏障,你可以根據現有的軟硬件環境對該閘門准入的併發流量進行動態的配置。
WCF對限流的控制是通過一個服務行爲(Service Behavior)實現的,該服務行爲類型名稱爲ServiceThrottlingBehavior,定義在System.ServiceModel.Description命名空間下。ServiceThrottlingBehavior定了三個整型的屬性:MaxConcurrentCalls、MaxConcurrentInstances和MaxConcurrentSessions。它們分別代表流量控制的三個閥值,簡單地說,我們所說的限流就是通過設置這三個值控制能夠處理的併發量。
二、MSDN關於三個限流閥值的介紹
基於.NET Framework 4.0的MSDN對上述三個限流閥值是這樣介紹的:
- MaxConcurrentCalls:獲取或設置一個值,該值指定整個 ServiceHost 中正在處理的最多消息數,默認值爲 16;
- MaxConcurrentInstances:獲取或設置一個值,該值指定服務中可以一次執行的最多 InstanceContext 對象數,默認值爲 26;
- MaxConcurrentSessions:獲取或設置一個指定 ServiceHost 對象可一次接受的最多會話數的值,默認值爲 10。
三、通過實例測試默認的最大併發會話數
通過ServiceThrottlingBehavior的MaxConcurrentSessions屬性表示的最大併發會話數默認爲10,果真如此嗎?我們不妨通過一個簡單的實例來驗證。照理以計算服務爲例,下面是契約接口和服務類型的定義。
1: [ServiceContract(Namespace ="http://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="http://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 值。分配給此操作的時間可能已經是更長超時的一部分。
四、WCF 4.0中三個限流默認閥值具體是多少呢?
通過上面演示的實例,我們發現默認情況下允許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。