[WCF编程]9.性能与限流

时间:2023-01-21 20:36:46

一、性能概述

WCF服务的性能取决于很多因素。出了CPU、RAM和网络性能等常见的因素外,实例上下文模式、并发模式、数据契约的设计或使用的绑定等与WCF有关的因素都起着重要的作用。

实例上下文模式用来控制服务对象的实例化行为有PerCall、PerSession和Singleton三种模式可供选择。

绑定决定了传输协议和编码格式。此外,通过绑定可以使用很多的WS*协议。

并发模式决定了是否允许多个线程同时访问同一个对象。并发模式是有[ServiceBehavior]特性来控制的,它的默认值为ConcurrencyMode.Single,其它选项还有ConcurrencyMode.Multiple和ConcurrencyMode.Reentrant。ConcurrencyMode.Single表示服务对象一次只允许一个线程访问,因此,此模式不会产生任何同步问题,因为其它请求会被自动插入到队列中,只有当线程释放了此对象之后,其它请求才可以访问它。ConcurrencyMode.Multiple模式允许任意多个线程同时访问一个对象。如有必要,必须通过手工方法用Monitor和Mutex等传统的.NET工具来控制线程的同步。

然而,原则上只有当使用一个多线程客户端(他访问一个PerSession对象),或者使用Single模式时,ConcurrencyMode才会起作用。当使用PerCall模式时,不管任何时候调用一个方法,都会创建一个新对象,这就从一开始就避免了多线程问题。

下面演示了[ServiceBehavior]特性的用法:

 [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,ConcurrencyMode=ConcurrencyMode.Single)]
public class Service6:IService6
{

二、限流

限流并非直接的实例管理技巧,它允许开发者限制客户端连接数以及服务的负荷。

限流让你可以避免服务过量分配和使用资源。当启用限流配置时,如果超过了限流就会自动把调用者放入等待队列中,让后一次处理这些请求。如果客户端在等待期间超时,就会获得TimeoutException异常。

每个服务类型都可以应用限流技术,也就是说,它会影响到服务的所有实例以及所有终结点。实现方式是为限流与服务使用的每个通道分发器建立关联。

WCF允许开发者控制下列服务参数:

  • 并发会话最大数(maxConcurrentSessions)

它指的是包含在服务传输层的一个会话所有独立的客户端数。简单的说,该数值表示使用TCP、IPC和任何一种WS绑定(具有可靠性、安全性)的独立客户端的最大数目。默认值为处理器计数(或内核)的100倍。

  • 并发调用最大数(maxConcurrentCall)

它指的限制所有服务实例当前正在执行的调用总数。通常来说,该值应该保持为会话最大值的1%或3%.默认值为处理器计数(或内核)的16倍。

  • 并发实例最大数(maxConcurrentInstances)

它指的控制并发上下文实例的数量。除非你显示设置了这个值,否则它会默认等于最大并发调用的数目和最大并发会话数目(单个处理器116个实例)之和。使用会话服务模式,最大的实例数量是并发获得实例和并发会话的总数量。当启用实例停止时,实例的数量有可能远少于上下文数,而且会在上下文数量到达并发实例最大数时阻塞客户端。使用单调服务模式,实例数目实际上与并发调用的数目一致。因此,单调服务模式实例的最大数目小于配置的最大并发数和并发调用数目。对于单例服务模式,这个值会忽略掉,因为它只有一个服务实例。

限流体现的是托管和部署的特征。设计一个服务时,可以不需要配置限流,认为服务能够承受客户端的负荷。这就是为什么限流行为特性易于实现,WCF却没有提供的原因。

配置限流

利用配置文件中Servicebehavior节点的<serviceThrottling>元素可以控制也可以使用编程方式进行控制。

以配置文件方式配置限流

<serviceBehaviors>
</behavior>
<behavior name="throttlingBehavior">
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="false"/>
<!--客户端验证方式-->
<serviceThrottling maxConcurrentSessions="400" maxConcurrentCalls="64" maxConcurrentInstances="464"/>
</behavior>
</serviceBehaviors>

以编程方式配置限流

ServiceHost host = new ServiceHost(typeof (Service.Service6));
ServiceThrottlingBehavior throttle;
throttle = host.Description.Behaviors.Find<ServiceThrottlingBehavior>();
if (throttle==null)
{
throttle = new ServiceThrottlingBehavior();
throttle.MaxConcurrentCalls = 64;
throttle.MaxConcurrentSessions = 400;
throttle.MaxConcurrentInstances = 464;
host.Description.Behaviors.Add(throttle);
}
host.Open();

读取限流

可使用以下代码来读取限流的值:

ServiceHost host = new ServiceHost(typeof (Service.Service6));
host.Open();
ChannelDispatcher dispatcher = host.ChannelDispatchers[0] as ChannelDispatcher;
Console.WriteLine("Max concurrten calls {0}",dispatcher.ServiceThrottle.MaxConcurrentCalls);
Console.WriteLine("Max concurrten instance {0}", dispatcher.ServiceThrottle.MaxConcurrentInstances);
Console.WriteLine("Max concurrten sessions {0}", dispatcher.ServiceThrottle.MaxConcurrentSessions); Console.Read();

在调试阶段,最重要的是定义一个基线。修改完配置文件之后哦,把新结果与这个基线进行比较,看看这些变化是否有正面影响,在服务器上整体负荷是否有下降。WCF提供了许多性能计数器一监视系统的性能或建立一个基线。在读取性能计数器之前,必须用配置方法或编程方法启动性能计数器。

如以下用配置文件方式配置性能计数器:

<system.serviceModel>
...
<diagnostics performanceCounters="All"/>
...
</system.serviceModel>

在启动性能计数器和服务宿主后,可以用Windows性能监视器来监视系统的当前性能;WCF也提供有一个监视器,用于监视服务的整体性能——终结点和操作的性能。

三、参考资料

《WCF服务编程》

《WCF4高级编程》

WCF Throttling 限流的三道闸口