閱讀489 返回首頁    go 阿裏雲 go 技術社區[雲棲]


WCF並發(Concurrency)的本質:同一個服務實例上下文(InstanceContext)同時處理多個服務調用請求

引言

服務(Service)的本質就是提供服務消費者期望的某種功能,服務的價值體現在兩個方麵:服務本身的質量和寄宿服務的平台應付消費者的數量,並發(Concurrency)的關注的是第二個要素。WCF服務寄宿於資源有限的環境中,要實現服務效用的最大化,需要考慮如何利用現有的資源實現最大的吞吐量(Throughput)。提高吞吐量就某個寄宿的服務實例(Service Instance)來說,一個重要的途徑就是讓它能夠同時處理來自各個客戶端(服務代理)的並發訪問。WCF實現了一套完整的並發控製體係,為你提供了不同的並發模式。

我經常說軟件架構是一門權衡的藝術,需要綜合考慮各種相互矛盾的因素,找到一種最優的組合方式。提高單個服務實例允許的並發訪問量能夠提高整體吞吐量,這樣的理論依賴於一種假設,那就是服務端所能使用的資源是無限。我們知道,這種假設無論在什麼情況下都不會成立。如果我們並發量超出了服務端所能承受的臨界點,整個服務端將會崩潰。所以,WCF一方麵需要允許讓單個服務實例並發處理接收到的多個請求,同時也需要設置一道閘門控製並發的數量。WCF的流量限製(Throttling)體係為你創建了這道閘門。

從本篇文章開始,我將發布一係列的文章對WCF並發架構體係進行深入剖析 ,先來看看並發的基本介紹。

一、同一個服務實例上下文同時處理多個服務調用請求

並發的含義就是多個並行的操作同時作用於一個相同的資源或者對象,或者說同一個資源或者對象同時應付多個並行的請求。對於WCF的並發來說,這裏將的“資源或者對象”指的就是承載服務操作最終執行的服務實例(Service Instance)。而WCF將服務實例封裝在一個稱為實例上下文(InstanceContext)對象中,所以WCF中的並發指的是同一個服務實例上下文同時處理多個服務調用請求。

WCF服務端框架一個主要的任務是將接收到的服務調用請求分發給激活的服務實例,調用相應的服務操作並返回執行結果。也就是說,服務操作的執行最終還是會落實到某個具體的服務實例上。《WCF技術剖析(卷1)》的第9章對WCF的實例化機製進行了深入的剖析,從中我們知道在WCF服務端框架體係中,激活的服務實例並不是單獨存在的,而是被封裝在一個被稱為實例上下文(InstanceContext)對象中。WCF提供了三種不同的實例上下模式(Per-Call、Per-Session和Single)實現了不同的服務實例上下文提供機製。

所以,WCF並發框架體係解決的是如何有效地處理被分發到同一個服務實例上下文的多個服務調用請求,這些並行的調用請求可能來自不同的客戶端(服務代理),也可能相同的客戶端。WCF並發的本質上可以通過圖1體現。

clip_image002

圖1 通過一個InstanceContext對多個並發請求的處理

由於WCF的並發處理屬於服務本身自身的行為,所以我們通過服務行為(Service Behavior)的形式對采取的並發策略進行控製,而不同的並發策略定義在相應的並發模式(Concurrency Mode)下麵。

二、通過ServiceBehaviorAttribute特性定義並發模式

WCF為三種典型的並發處理策略定義了三種典型的並發模式,即Single、Reentrant和Multiple。這三種並發模式通過ConcurrencyMode的三個同名的枚舉項表示,ConcurrencyMode定義如下:

   1: public enum ConcurrencyMode
   2: {
   3:     Single,
   4:     Reentrant,
   5:     Multiple
   6: }

通過ConcurrencyMode枚舉項表示的三種不同的並發模式體現了WCF處理並發請求的三種不同能策略:

  • Single一個封裝了服務實例的InstanceContext對象在某個時刻隻能用於對某一個單一請求的處理,或者說針對某個InstanceContext對象的多個並發的請求會以一種串行的方式進行處理。具體來講,當WCF服務端框架接收到多個針對相同InstanceContext的請求時,會先確定該InstanceContext是否可用(是否正在處理之前的服務調用請求),如何可用,則將接收到的第一個請求分發給它,其它請求則被放入根據抵達的先後順序被放入到一個隊列中。如果之前的請求被正常處理,隊列中的第一個請求被分發給InsanceContext。如果一個請求在隊列中等待的時間過長,超過了設置好的服務調用的超時實現,客戶端會跑出TimeoutException異常;
  • Reentrant該模式和Single一樣,InstanceContext對象在某個時刻隻能用於對某一個單一請求的處理。不過有一點不同的是,如果服務操作在執行過程中涉及對外調用(Call Out),該InstanceContext可以用於其它服務調用請求的處理;
  • Multiple在該模式下,一個InstanceContext可以同時用於處理多個服務請求,所以Multiple並發模式下針對同一個InstanceContext的多個並發請求能夠得到及時的處理。不過,由於是並行的處理方式,服務操作執行過程中狀態的管理以及多線程的安全問題需要服務開發者自行處理。

並發模式的采用是服務單邊的選擇,是服務端個人的行為,所以並發模式以服務行為的方式定義,我們隻需要在服務類型上應用ServiceBehaviorAttribute特性,為ConcurrencyMode屬性設置相應的值即可,ServiceBehaviorAttribute定義如下:

   1: [AttributeUsage(AttributeTargets.Class)]
   2: public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
   3: {
   4:     //其它成員
   5:     public ConcurrencyMode ConcurrencyMode { get; set; }
   6: }

如果顯示指定服務采用的並發模式,默認使用的是ConcurrencyMode.Single,所以下麵兩種服務定義方式是等效的。

   1: public class CalculatorService : ICalculator
   2: {
   3:     //省略成員
   4: }
   5:  
   6: [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
   7: public class CalculatorService : ICalculator
   8: {
   9:     //省略成員
  10: }

三、回調(Callback)中的並發

WCF並發解決的是同一個InstanceContext對象在處理並發請求是采用怎樣的處理策略。我們知道InstanceContext不僅僅是封裝真正服務實例的容器,當我們通過雙向通信的機製從服務端回調客戶端操作時,真正執行回調操作的回調對象也是封裝在InstanceContext中。

在雙向通信的場景中,如果多個服務端或者同一個客戶端的多個並發的服務調用操作所指定的回調實例上下文(即封裝回調操作的InstanceContext對象),就可能出現針對同一個InstanceContext的並發回調的現象。WCF采用與正常服務調用相同的機製來處理並發回調,實際上WCF采用幾乎一樣的機製來實現正常的服務調用和回調。

與通過將ServiceBehaviorAttribute特性應用到服務類型並指定采用的並發模式相類似,回調采用的並發模式通過應用在回調類型上的CallbackBehaviorAttribute特性來指定。CallbackBehaviorAttribute中同樣定義了ConcurrencyMode屬性:

   1: [AttributeUsage(AttributeTargets.Class)]
   2: public sealed class CallbackBehaviorAttribute : Attribute, IServiceBehavior
   3: {
   4:     //其它成員
   5:     public ConcurrencyMode ConcurrencyMode { get; set; }
   6: }

下麵的代用中,我們通過在回調類型CalculatorCallbackService上應用CallbackBehaviorAttribute特性,將回調並發模式設置成ConcurrencyMode.Multiple。

   1: [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
   2: public class CalculatorCallbackService:ICalculatorCallback
   3: {
   4:     //省略成員
   5: }

四、 事務行為與並發

相信你還會記得在上麵一章介紹事務編程(《上篇》、《中篇》、《下篇》)的時候,可以在服務類型上麵應用ServiceBehaviorAttribute特性將ReleaseServiceInstanceOnTransactionComplete屬性設成True,這樣可以讓WCF在事務結束之後將封裝了服務實例的InstanceContext對象釋放掉。不過這樣的設置之後再並發模式為ConcurrencyMode.Single的前提下方才有效,否則在進行服務寄宿的時候將會拋出異常。

比如說,我們定了如下一個BankingService服務類型,通過ServiceBehaviorAttribute特性指定ReleaseServiceInstanceOnTransactionComplete為True,並采用ConcurrencyMode.Multiple並發模式。

   1: [ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = true,ConcurrencyMode = ConcurrencyMode.Multiple)]
   2: public class BankingService : IBankingService
   3: {
   4:     [OperationBehavior(TransactionScopeRequired = true)]
   5:     public void Transfer(string accountFrom, string accountTo, decimal amount)
   6:     {
   7:        //省略實現
   8:     }
   9: }

當我們試圖寄宿該BankingService服務的時候,如圖2所示的InvalidOperationException異常會被拋出,並提示對於已經將ReleaseServiceInstanceOnTransactionComplete設置成True的服務來說,必須將並發模式設成ConcurrencyMode.Multiple。

clip_image004

圖2 在Multiple+ReleaseServiceInstanceOnTransactionComplete導致的異常 

WCF提供的三種不同的並發模式,使開發者可以根據具體的情況選擇不同的並發處理的策略。對於這三種並發模式,Multiple采用的並行的執行方式,而Single和Reentrant則是采用串行的執行方式。串行執行即同步執行,在WCF並發框架體係中,這樣的同步機製是如何實現的呢?請關注下篇文章


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

最後更新:2017-10-27 15:05:13

  上一篇:go  【幹掉英偉達?】DeepMind CEO哈薩比斯投資的AI芯片,性能超越GPU 100倍
  下一篇:go  並發中的同步--WCF並發體係的同步機製實現