相關閱讀 |
>>> 技術話題—商業文明的嶄新時代 >>> | 簡體 傳統 |
我們期望WCF服務端能夠處理盡可能多的并發請求,但是資源是有限的,服務不可能同時處理無限多的并發請求,如果WCF不控制進入消息處理系統的并發量,一旦超過臨界值,整個服務端將會由于資源耗盡而崩潰,所以WCF提供了一個限流Throttling特性,讓我們可以根據不同性能的服務器來配置最佳的并發流量限制,這三個值相當于WCF通道的三個閘口,每個值代表各自閘口的計數器,當各閘口監控的計數達到你所設置的閾值,后續的請求將會進入到服務的等待隊列,所以,如果此值設置過小了,則大量并發請求時不能被及時處理而進入到等待隊列中,很容易出現超時的情況,如果值設置過大,則會出現WCF處理不過來的情況,容易導致服務崩潰,所以,對于高低配置處理能力不同的服務器,需要分別設置閾值。
通過反編譯和MSDN幫助得知,三個屬性解釋和默認值如下:
MaxConcurrentCalls
|
該值指定整個 ServiceHost 中正在處理的最多消息數
|
16 * CPU核心數
|
MaxConcurrentSessions
|
指定 ServiceHost 對象可一次接受的最多會話數的值
|
100 * CPU核心數
|
MaxConcurrentInstances
|
該值指定服務中可以一次執行的最多 InstanceContext 對象數
|
MaxConcurrentCalls+MaxConcurrentSession
|
從System.ServiceModel.dll 反編譯的代碼來看,默認值的邏輯確實如此。
但,你可能會想,一個ServiceHost默認正在處理的消息數才16,未免太少了吧,別担心,反編譯代碼再細看可知,MaxConcurrentCalls和MaxConcurrentSessions的默認值與CPU核數是相關的,假如你的系統配置是4核電腦,則MaxConcurrentCalls默認值等于16*4,MaxConcurrentSessions默認值等于 100*4,maxConcurrentInstances默認值等于64+400,假如你對此默認值還覺得不適當,需要顯式設置的話,建議以默認值為準繩進行增減設置,MSDN Library 的建議是設置比16 * cpu核數要大的數值,總的來說,閾值設置多大,還需根據生產環境情況和經驗來把握,值得注意的是,顯式配置的時候,值是需要是經過與cpu核心數乘法計算后的值,因為WCF不會再去乘以你所顯式設定的值的。
一個完整的ServiceThrottling配置如下,如采取默認,則將<ServiceThrottling>節點去掉,你也可以單獨只設定某個屬性,其他屬性則自動采用默認值,除了以配置的形式外,還可以通過代碼來進行設定,這里不做敘述。
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceThrottling maxConcurrentCalls="16" maxConcurrentSessions="100" maxConcurrentInstances="116"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
我在研究ServiceThrottling特性的時候搜了很多資料,發現很少,幾乎是沒有一篇是說三個流量閾值該設置多少才合適、如何去驗證配置前后的效果等,這讓我當時有一種感嘆:世界上最難的事情并不是找出正確的答案,而是讓你找出證明你答案是正確的證據。
后來發現使用windows的性能監視器可以監控到WCFService的執行情況,我使用的是ServiceModelService 4.0.0.0 的Calls OutStanding計數器,能監控正在進行的調用的次數,其他關于WCF的計數器請參閱文末的參考資料;Windows性能監視器可以在管理工具->性能監視器 打開,除了實時監控外,還可以生成日志文件,實乃監控運維的一大利器,關于性能監視器的詳細用法請自行搜索資料。
我的測試服務接口所做的操作是,Thread.Sleep 3秒,然后客戶端大量并發請求,通過修改MaxConCurrentCalls的值觀察實驗效果:
1、 當將MaxConcurrentCalls設置為1的時候,服務將以串行化執行,監控結果顯示正在進行的調用次數一直都為1;
2、 當將MaxConcurrentCalls設置為30的時候,WCF服務的處理能力明顯提到,當調用次數在提升階段時,證明WCF的處理能力在預設的閾值之內,當達到峰頂閾值30后,后續來的請求發現此時的WCF同時處理請求的能力已經達到預設的閾值了,就會進入到等待隊列中去,等待調度,當等待隊列中的請求慢慢被處理完后,此時計數器也會進行減法處理,以便讓后續來的請求知道,你這個服務到底有沒有能力馬上“接待”我,從下圖可以看出,如果MaxConCurrentCalls設置過小的話,就會很容易限制了WCF的處理能力,出現瓶頸。
maxConcurrentSessions的作用是指定 ServiceHost 對象可一次接受的最多會話數的值,默認值為100 * CPU核心數,所以,我們的測試示例使用的接口Binding必須是支持Session的,不能使用basicHttpBinding,因為他不支持session會話,如果Binding不支持會話,則此屬性的設置也就無效了,這里我使用的Binding是wsHttpBinding。
using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorservice")) { bool stop = false; for (int i = 0; i < 1000 && !stop; i++) { ICalculator calcultor = channelFactory.CreateChannel(); try { calcultor.Add(1, 2); Console.WriteLine("第{0}個服務代理調用成功!", i + 1); } catch (Exception ex) { Console.WriteLine("出現異常:{0}", ex.Message); stop = true; } } }
我們通過基于客戶端終結點配置名稱創建的ChannelFactory<TChannel>對象創建了1000個服務代理進行用其進行1000次服務調用。當上面這個實例運行的時候,客戶端控制臺將會出現如下的輸出結果,實例程序清晰地反映了這樣的事實:雖然我們通過不同的服務代理對象進行了1000次服務調用,但是只有前面400是成功的,第401個請求將一直等待被處理,直到達到超時時間為止,在這里我沒有配置maxConcurrentSessions值,所以限流閾值采用的是默認值100 乘以我的電腦CPU核心數4,也就是400。
在這里對蔣金楠表示感謝,不僅僅是在查詢WCF相關資料的時候經常會搜到你的文章,對我有很大的幫助,而且上次你在博客園發起的整點搶評論贈書活動中送了我一本《ASP.NET Web API 2 框架揭秘》,據說很快會做一個《ASP.NET MVC5 框架揭秘》的搶評活動!
MSDN:MaxConcurrentInstances 屬性指定服務中 InstanceContext 對象的最大數目。 牢記 MaxConcurrentInstances 屬性和InstanceContextMode 屬性之間的關系很重要。 如果 InstanceContextMode 為 PerSession,則結果值將為總會話數。 如果InstanceContextMode 為 PerCall,則結果值將為并發調用的數量。 如果消息到達時,InstanceContext 對象的數目已經達到最大數量,則將保存該消息,直至有 InstanceContext 對象關閉。
InstanceContextMode是特性ServiceBehavior中的一個枚舉屬性,ServiceBehavior特性指定服務協定實現的內部執行行為,一般這樣使用。
既然MaxConCurrentInstances與InstanceContextMode關系密切,先來看看這個枚舉,很明顯PerSession 與PerCall 的區別是,PerSession 為每個會話創建一個新的System.ServiceModel.InstanceContext對象,而PerCall則會在每次調用前創建,調用后回收。
//指定可用來處理包含在傳入消息中的調用的服務實例數。 public enum InstanceContextMode { //為每個會話創建一個新的 System.ServiceModel.InstanceContext 對象。 PerSession = 0, //新的 System.ServiceModel.InstanceContext 對象在每次調用前創建,在調用后回收。如果信道未創建會話,則該值的行為就如同 PerCall = 1, //只有一個 System.ServiceModel.InstanceContext 對象用于所有傳入呼叫,并且在調用后不回收。如果服務對象不存在,則創建一個。 Single = 2, }
以上,我們得知WCF的限流特性以及三個限流閘口各自限制的對象,還可以通過Windows性能監視器來監控服務的情況,對于WCF Throttling,我個人建議是讓其采取默認的配置,因為其默認值中考慮到了CPU核心數,考慮到了不同配置服務器的情況,而且還可以不必在每臺服務器上修改配置,但同時MSDN也提到,WCF Throttling的設置也是需要依靠經驗來,所以,如果采用默認配置的情況下出現瓶頸現象和處理能力不足的情況,不妨根據每臺服務器的情況,顯式增加閾值。
乘以CPU核心數的好處就是部署在不同配置的服務器上,都無需再修改配置。
We also bumped up the value for MaxConcurrentSessions from 10 to 100. Based on customer’s feedback, this change fits the need for most applications.
Please note, these changes are for the default settings only. If you explicitly set these settings in either configuration or in code, the system would use the settings that you provided. No “ProcessCount” multiplier would be applied.
* CPU核心數 的改變只適用于默認配置,如果你修改配置的話,就不適用于核心數相乘。需要你自己乘以核心數然后配置上去 。
dotnetgeek 2015-05-19 00:29:15
稱謂:
内容: