WCF - ServiceThrottlingBehavior

来源:互联网 发布:宏观经济数据 知乎 编辑:程序博客网 时间:2024/06/06 13:13

ServiceThrottlingBehavior 允许我们为服务宿主设置一个"安全阀",用于避免恶意或意外的大量并发摧毁服务器。我们可以设置同一时刻最多可以创建的服务实例数量,最多可创建的会话数量,以及所有服务实例并发调用总量。当超出这些阀值时,WCF 会让客户端调用进入一个等待队列,直至获取执行授权。如果等待超时,客户端代理会触发TimeoutException 异常。

ServiceThrottlingBehavior 的三个属性参数分别对应上面所说的三种情况。

  • MaxConcurrentInstances : 设置同一时刻服务上下文实例的最大数量。( 限制服务并发实例数量。缺省 Int32.MaxValue。)
  • MaxConcurrentSessions : 设置同一时刻可以接受的最大会话数量。(限制并发会话数量。缺省 10。)
  • MaxConcurrentCalls : 设置 ServiceHost 消息并发处理的最大值。 (限制所有服务实例并发调用总数量,缺省 64。)

下面我们写个例子来验证一下,我们将 MaxConcurrentInstances 设置为 1,用多线程模拟 5 个客户端进行并发。

测试原型

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IContract
{
  [OperationContract]
  void Test();
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IContract, IDisposable
{
  public MyService()
  {
    Console.WriteLine("Constructor:{0}", OperationContext.Current.SessionId);
  }

  public void Dispose()
  {
    Console.WriteLine("Dispose...");
  }

  public void Test()
  {
    Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
    Thread.Sleep(2000);
  }
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://localhost:8080/MyService"));
      host.AddServiceEndpoint(typeof(IContract), new WSHttpBinding(), "");
      host.Open();
    });

    for (int i = 0; i < 5; i++)
    {
      new Thread(delegate()
      {
        IContract channel = ChannelFactory<IContract>.CreateChannel(new WSHttpBinding(),
          new EndpointAddress("http://localhost:8080/MyService"));
        using (channel as IDisposable)
        {
          channel.Test();
        }
      }).Start();
    }
  }
}


输出:
Constructor:urn:uuid:6014cb54-9f44-4d16-8488-6841b682030b
Constructor:urn:uuid:7d6ca245-7d10-48ec-8619-d332cdb567b9
Constructor:urn:uuid:f64f973d-7361-4eea-8fbd-5244a4306957
Constructor:urn:uuid:ce8c2810-fc73-4419-aa65-e41617e416c4
Test:urn:uuid:ce8c2810-fc73-4419-aa65-e41617e416c4
Test:urn:uuid:6014cb54-9f44-4d16-8488-6841b682030b
Test:urn:uuid:f64f973d-7361-4eea-8fbd-5244a4306957
Test:urn:uuid:7d6ca245-7d10-48ec-8619-d332cdb567b9
Constructor:urn:uuid:333d06db-9751-4e35-be7a-1ea791c31da4
Test:urn:uuid:333d06db-9751-4e35-be7a-1ea791c31da4
Dispose...
Dispose...
Dispose...
Dispose...
Dispose...

并发控制

AppDomain.CreateDomain("Server").DoCallBack(delegate
{
  ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://localhost:8080/MyService"));
  host.AddServiceEndpoint(typeof(IContract), new WSHttpBinding(), "");

  ServiceThrottlingBehavior throttling = new ServiceThrottlingBehavior();
  throttling.MaxConcurrentInstances = 1;
  host.Description.Behaviors.Add(throttling);

  host.Open();
});

for (int i = 0; i < 5; i++)
{
  new Thread(delegate()
  {
    IContract channel = ChannelFactory<IContract>.CreateChannel(new WSHttpBinding(),
      new EndpointAddress("http://localhost:8080/MyService"));

    using (channel as IDisposable)
    {
      channel.Test();
    }
  }).Start();
}


输出:
Constructor:urn:uuid:aadd2b1f-b394-4039-a680-321c8d3f01ef
Test:urn:uuid:aadd2b1f-b394-4039-a680-321c8d3f01ef
Dispose...
Constructor:urn:uuid:d26243d1-9157-4b6d-b074-a99a6aba96b3
Test:urn:uuid:d26243d1-9157-4b6d-b074-a99a6aba96b3
Dispose...
Constructor:urn:uuid:4d01794b-efc3-4ae7-b8e2-842f6b0fa1fc
Test:urn:uuid:4d01794b-efc3-4ae7-b8e2-842f6b0fa1fc
Dispose...
Constructor:urn:uuid:e63170f1-2d37-434c-8ee4-10a714a3bb9e
Test:urn:uuid:e63170f1-2d37-434c-8ee4-10a714a3bb9e
Dispose...
Constructor:urn:uuid:a28e13a6-0fdf-4d8b-9c1b-fc45ef7d0f28
Test:urn:uuid:a28e13a6-0fdf-4d8b-9c1b-fc45ef7d0f28
Dispose...

对比前后输出的结果,我们可以很清楚的看到并发控制带来的效果。其他两个参数的使用方法类似,本文不做进一步描述。

原创粉丝点击