WCF是一个基于多线程的消息监听、接收和处理框架体系,能够同时应付来自相同或者不同客户端的服务调用请求,并提供完善的同步机制确保状态的一致性。一方面,我们期望WCF服务端能够处理尽可能多的并发请求,但是资源的有限性决定了并发量有一个最大值。如果WCF不控制进入消息处理系统的并发量,试图处理所有抵达的并发请求,一旦超过了这个临界值,整个服务端将会由于资源耗尽而崩溃。
所以,我们需要在WCF的消息接收系统和消息处理系统之间设置一道道屏障,将流入消息处理系统的请求控制到一个最佳的范围,以实现对现有资源的有效利用,从而达到确保服务的可用性和提高整体吞吐量的目的。WCF的流向限制(Throttling)为你设置了这些屏障,你可以根据现有的软硬件环境对该闸门准入的并发流量进行动态的配置。我们先来看看如何进行限流控制。
一、如何进行限流控制
WCF对限流的控制是通过一个服务行为(Service Behavior)实现的,该服务行为类型名称为ServiceThrottlingBehavior,定义在System.ServiceModel.Description命名空间下。我们先来看看ServiceThrottlingBehavior的定义:
代码语言:js复制 1: public class ServiceThrottlingBehavior : IServiceBehavior
2: {
3: public ServiceThrottlingBehavior();
4: void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters);
5: void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase);
6: void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase);
7:
8: public int MaxConcurrentCalls { get; set; }
9: public int MaxConcurrentInstances { get; set; }
10: public int MaxConcurrentSessions { get; set; }
11: }
从上面的代码中我们可以看到,ServiceThrottlingBehavior定了三个整型的属性:MaxConcurrentCalls、MaxConcurrentInstances和MaxConcurrentSessions。它们分别代表流量控制的三个阀值,简单地说,我们所说的限流就是通过设置这三个值控制能够处理的并发量。这三个属性所代表的数值是针对某个ServiceHost而言的。接下来,我们来简单地说说这个阀值具体代表什么含义:
- MaxConcurrentCalls:当前ServiceHost能够处理的最大并发消息数量,默认值为16;
- MaxConcurrentInstances:当前ServiceHost允许存在的InstanceContext的最大数量,默认值为26;
- MaxConcurrentSessions:当前ServiceHost允许的最大并发会话数量,默认值为10。
由于控制流量的ServiceThrottlingBehavior是一个服务行为,我们可以通过编程和配置的方式对上述的三个允许的最大并发值进行设置。
二、通过编程的方式设置最大并发值
由于控制流量的ServiceThrottlingBehavior是一个服务行为,我们在进行服务寄宿(自我寄宿)的时候,直接通过编程的方式将该服务行为添加到服务描述的行为列表之中。在下面的服务寄宿代码中,我们将CalculatorService服务的MaxConcurrentCalls、MaxConcurrentSessions和MaxConcurrentInstances分别设置成50、30和20。需要注意的是,所有的设置必须在开启ServiceHost(调用Open方法)之前完成方能生效。在ServiceHost开启的状态下的什么限流设置均是无效的,至于具体的原因,可以参考《WCF技术剖析(卷1)》第7章关于服务描述和服务寄宿过程相关内容。
代码语言:js复制 1: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
2: {
3: ServiceThrottlingBehavior throttlingBehavior = host.Description.Behaviors.Find<ServiceThrottlingBehavior>();
4: if (null == throttlingBehavior)
5: {
6: throttlingBehavior = new ServiceThrottlingBehavior();
7: host.Description.Behaviors.Add(throttlingBehavior);
8: }
9:
10: throttlingBehavior.MaxConcurrentCalls = 50;
11: throttlingBehavior.MaxConcurrentInstances = 30;
12: throttlingBehavior.MaxConcurrentSessions = 20;
13:
14: host.Open();
15: Console.Read();
16: }
不过我们很少通过编程的方式进行限流的控制,更多地,还是采用配置的方式。
三、通过配置的方式设置最大并发量
基本上所有服务行为均可用通过配置的方式应用到相应的服务上面,上述的关于限流的三个最大并发量通常都是采用配置的方式进行设置的。对于系统定义的服务行为来说,WCF均会为其定义相应的配置元素。同理,如果我们希望通过配置的方式应用自定义的服务行为,我们也需要定义相应的配置元素。ServiceThrottlingBehavior的配置元素定义在ServiceThrottlingElement类型中,在具体介绍限流配置之前,我们不妨先来看看ServiceThrottlingElement的定义:
代码语言:js复制 1: public sealed class ServiceThrottlingElement : BehaviorExtensionElement
2: {
3: //其他成员
4: [ConfigurationProperty("maxConcurrentCalls", DefaultValue = 16)]
5: public int MaxConcurrentCalls { get; set; }
6:
7: [ConfigurationProperty("maxConcurrentInstances", DefaultValue = 26)]
8: public int MaxConcurrentInstances { get; set; }
9:
10: [ConfigurationProperty("maxConcurrentSessions", DefaultValue = 10)]
11: public int MaxConcurrentSessions { get; set; }
12: }
ServiceThrottlingElement的定义暴露了ServiceThrottlingBehavior对应配置项的结构。实际上,整个配置项由单纯的三个配置属性构成,它们分别代表上述的三的最大并发值。此外,ServiceThrottlingElement还透露给我们 一个重要的信息,就是这三个最大并发量的默认值。MaxConcurrentCalls、MaxConcurrentInstances和MaxConcurrentSessions在默认的情况下的值为16、26和10,这和上面的介绍是一致的。
如果通过配置的方式控制限流,我们只需要将ServiceThrottlingBehavior对应的配置,即通过ServiceThrottlingElement定义的配置元素定义在相应的服务行为配置中即可,相应配置项的名称为serviceThrottling。通过下面的配置,我将CalculatorService的三个最大并发量(MaxConcurrentCalls、MaxConcurrentInstances和MaxConcurrentSessions)分别设置为50、30和20。
代码语言:js复制 1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.serviceModel>
4: <behaviors>
5: <serviceBehaviors>
6: <behavior name="throttlingBehavior">
7: <serviceThrottling maxConcurrentCalls="50" maxConcurrentInstances="30" maxConcurrentSessions="20" />
8: </behavior>
9: </serviceBehaviors>
10: </behaviors>
11: <services>
12: <service behaviorConfiguration="throttlingBehavior" name="Artech.ConcurrentServiceInvocation.Service.CalculatorService">
13: <endpoint address="http://127.0.0.1:8888/calculatorservice" binding="basicHttpBinding" contract="Artech.ConcurrentServiceInvocation.Service.Interface.ICalculator" />
14: </service>
15: </services>
16: </system.serviceModel>
17: </configuration>
通过上面介绍,我们知道了如何通过编程和配置的方式设置相应的最大并发量,从而指导WCF的限流体系按照你设定的值对并发的服务调用请求进行限流控制。那么,在WCF框架体系内部,整个过程是如何实现的呢?请听下回分解。