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体现。

图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。

图2 在Multiple+ReleaseServiceInstanceOnTransactionComplete导致的异常 

WCF提供的三种不同的并发模式,使开发者可以根据具体的情况选择不同的并发处理的策略。对于这三种并发模式,Multiple采用的并行的执行方式,而Single和Reentrant则是采用串行的执行方式。串行执行即同步执行,在WCF并发框架体系中,这样的同步机制是如何实现的呢?请关注下篇文章

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文链接

时间: 2024-11-03 17:47:35

WCF并发(Concurrency)的本质:同一个服务实例上下文(InstanceContext)同时处理多个服务调用请求的相关文章

WCF并发(Concurrency)的本质

---同一个服务实例上下文(InstanceContext)同时处理多个服务调用请求 引言 服务(Service)的本质就是提供服务消费者期望的某种功能,服务的价值体现在两个方面:服务本身的质量和寄宿服务的平台应付消 费者的数量,并发(Concurrency)的关注的是第二个要素.WCF服务寄宿于资源有限的环境中,要实现服务效用的最大化,需要考虑如何 利用现有的资源实现最大的吞吐量(Throughput).提高吞吐量就某个寄宿的服务实例(Service Instance)来说,一个重要的途径就是

并发与实例上下文模式: WCF服务在不同实例上下文模式下的并发表现

由于WCF的并发是针对某个封装了服务实例的InstanceContext而言的,所以在不同的实例上下文模式下,会表现出不同的并发行为.接 下来,我们从具体的实例上下文模式的角度来剖析WCF的并发,如果对WCF实例上下文模式和实例上下文提供机制不了解的话,请参阅<WCF 技术剖析(卷1)>第9章. 在<实践重于理论>一文中,我写一个了简单的WCF应用,通过这个应用我们可以很清楚了监控客户端和服务操作的执行情况下.借此 ,我们可以和直观地看到服务端对于并发的服务调用请求,到底采用的是并

WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇]

在[第2篇]中,我们深入剖析了单调(PerCall)模式下WCF对服务实例生命周期的控制,现在我们来讨轮另一种极端的服务实例上下文模式:单例(Single)模式.在单例模式下,WCF通过创建一个唯一的服务实例来处理所有的客户端服务调用请求.这是一个极端的服务实例激活方式,由于服务实例的唯一性,所有客户端每次调用的状态能够被保存下来,但是当前的状态是所有客户端作用于服务实例的结果,而不能反映出具体某个客户端多次调用后的状态.WCF是一个典型的多线程的通信框架,对并发的服务调用请求是最基本的能力和要

ConcurrencyMode.Multiple模式下的WCF服务就一定是并发执行的吗:探讨同步上下文对并发的影响[上篇]

在<并发与实例上下文模式>中,我们通过实例演示的方式讲述了基于不同实例上下文模式的并发行为.对于这个实例中的服务类型CalculatorService,读者应该还记得我们对它进行了特别的定义:通过ServiceBehaviorAttribute特性将属性将UseSynchronizationContext设置成False.至于为何要这么做,这就是本篇文章需要为你讲述的内容.为了让读者对本节介绍的内容有一个深刻的认识,我们不然去掉ServiceBehaviorAttribute特性的UseSyn

WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇]

在[第2篇]中,我们深入剖析了单调(PerCall)模式下WCF对服务实例生命周期的控制,现在我们来讨轮另一种极端的服务实例上下文模式:单例(Single)模式.在单例模式下,WCF通过创建一个唯一的服务实例来处理所有的客户端服务调用请求.这是一个极端的服务实例激活方式,由于服务实例的唯一性,所有客户端每次调用的状态能够被保存下来,但是当前的状态是所有客户端作用于服务实例的结果,而不能反映出具体某个客户端多次调用后的状态.WCF是一个典型的多线程的通信框架,对并发的服务调用请求是最基本的能力和要

WCF分布式开发步步为赢(9):WCF服务实例激活类型编程与开发

.Net Remoting的激活方式也有三种:SingleTon模式.SingleCall模式.客户端激活方式,WCF服务实例激活类型包括三种方式:单调服务(Call Service),会话服务(Sessionful Service),单例服务(Singleton Service).他们之间有什么联系.WCF服务激活类型的优势和缺点,以及如何在项目里编程开发和设置服务实例.全文分为5个部分,首先一次介绍单调服务(Call Service),会话服务(Sessionful Service),单例服

ConcurrencyMode.Multiple 模式下的WCF服务就一定是并发执行的吗:探讨同步上下文对并发的影响[下篇]

在<上篇>中,我通过一个具体的实例演示了WCF服务宿主的同步上下文对并发的影响,并简单地介绍了同步上下文是什么东东,以及同步上下文在多线程中的应用.那么,同步上下文在WCF并发体系的内部是如何影响服务操作的执行的呢?这实际上涉及到WCF的一个话题,即线程的亲和性(Thread Affinity),本篇文章将为你剖析WCF线程亲和机制的本质. 一.WCF线程亲和性(Thread Affinity) 对于服务端来说,WCF消息监听和接收体系通过IO线程池并发的处理来自客户端的服务调用请求,所以并发

[WCF 4.0新特性] 路由服务[实例篇]

在本篇文章中,我们将通过一个具体的实例来演示如何通过路由服务.在这个例子中,我们会创建连个简单的服务HelloServie和GoodbyeService.假设客户端不能直接调用这两个服务,需要使用到路由服务作为两者之间的中介.整个消息路由的场景如下图所示,中间的GreetingService.svc就是代表路由服务,而两个目标服务则通过HelloServie.svc和GoodbyeService.svc表示.路由服务使用的消息筛选器EndpointAddressMessageFilter,即根据

WCF中如何为客户端的多服务实例的调用实现统一的标识?

问题描述 服务端:服务契约IService1与IService2,分别有相应服务实现客户端:在同一机器上使用ChannelFactory<TService>创建这两种服务并调用问:服务端如何知道来自客户端的2个调用来自同一台机器?使用OperationContext.Current.SessionId试过了,不同,无法实现. 解决方案 解决方案二:引入SESSION也成呀.解决方案三:引用1楼的回复: 引入SESSION也成呀. 如何引用?解决方案四:试验一下这个好用不://GetClient