2013-04-21 96 views
1

我们在IIS上设计一个WCF Web服务,具有以下特点:选择一个WCF实例管理

  • 对象的创建是比较重(大约需要500毫秒),因为它需要编写一个文件
  • 任何国家在创建对象后需要保留
  • 来自客户端的每次呼叫平均需要150-200毫秒。这个调用包括发送UDP请求到另一台服务器并接收响应。
  • 我们预计约有30个同时进行的客户。它可能增长到50个客户。在最坏的情况下(50个客户端),我们需要一个包含10个对象实例的池来处理这个负载。

您会推荐3个实例管理上下文(PerCall,PerSession,Single)中的哪一个?为什么?哪个实例使我们能够管理可以完成这项工作的可用对象池?

回答

3

开箱即用,WCF不支持服务对象池。您需要自定义IInstanceProvider。在这种情况下,WCF上下文模式将定义WCF何时从IInstanceProvider请求新对象,并且IInstanceProvider行为将管理该池。根据使用情况将服务设置为PerInstance或PerSession可能有意义。

如果您在您的实现使用依赖注入容器,如Castle WindsorStructureMap,或MS企业库的Unity那么你可以使用容器的exsiting IInstanceProvider与汇集的生活方式。所有这些容器都是合理的(尽管我个人对管理对象池没有多少经验)。

我个人选择的容器是温莎城堡。在这种情况下,您可以使用Windsor的WCF Integration Facilitypooled lifestyle

这是一个使用Castle.Facilites.WcfIntegraion NuGet包的快速测试控制台程序。

using Castle.Facilities.WcfIntegration; 
using Castle.MicroKernel.Registration; 
using Castle.Windsor; 
using System; 
using System.Collections.Generic; 
using System.ServiceModel; 
using System.Threading.Tasks; 

namespace WCFWindsorPooledService 
{ 
    [ServiceContract] 
    public interface ISimple 
    { 
     [OperationContract] 
     void Default(string s); 
    } 

    public class SimpleService : ISimple 
    { 
     private static int CurrentIndex = 0; 
     private int myIndex; 

     public SimpleService() 
     { 
      // output which instance handled the call. 
      myIndex = System.Threading.Interlocked.Increment(ref CurrentIndex); 
     } 

     public void Default(string s) 
     { 
      Console.WriteLine("Called #" + myIndex); 
      System.Threading.Thread.Sleep(5); 
     } 
    } 

    class PooledService 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("\n\n" + System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType.Name); 

      // define mapping of interfaces to implementation types in Windsor container. 
      IWindsorContainer container = new WindsorContainer(); 
      container.AddFacility<WcfFacility>() 
        .Register(Component.For<SimpleService>().LifeStyle.PooledWithSize(2, 5)); 

      var host = new Castle.Facilities.WcfIntegration.DefaultServiceHostFactory() 
                  .CreateServiceHost(typeof(SimpleService).AssemblyQualifiedName, 
                       new Uri[] { new Uri("http://localhost/Simple") }); 
      host.Open(); 

      ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(host.Description.Endpoints[0]); 

      List<Task> tasks = new List<Task>(); 
      for (int i = 0; i < 20; i++) 
      { 
       tasks.Add(Task.Run(() => 
       { 
        ISimple proxy = factory.CreateChannel(); 
        proxy.Default("Hello"); 

        ((ICommunicationObject)proxy).Shutdown(); 
       })); 
      } 

      Task.WaitAll(tasks.ToArray()); 

      ((ICommunicationObject)host).Shutdown(); 
      container.Dispose(); 
     } 
    } 

    public static class Extensions 
    { 
     static public void Shutdown(this ICommunicationObject obj) 
     { 
      try 
      { 
       obj.Close(); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Shutdown exception: {0}", ex.Message); 
       obj.Abort(); 
      } 
     } 
    } 
} 

我不会假装理解城堡如何管理游泳池的所有规则,但游泳池显然正在使用。输出是:

PooledService 
Called #1 
Called #5 
Called #2 
Called #3 
Called #4 
Called #6 
Called #7 
Called #8 
Called #7 
Called #4 
Called #2 
Called #5 
Called #1 
Called #10 
Called #6 
Called #9 
Called #4 
Called #7 
Called #1 
Called #9 
+0

@ ErnieL:谢谢你的指导。就线程问题而言,看起来有效的是进入IIS管理器,选择应用程序池高级设置,并增加过程模型最大工作者进程。我仍然有关于使用哪个实例管理的问题。 – 2013-04-30 11:32:36

+0

@ Mr.T。增加工作进程的数量只会创建更多的进程来处理请求。它不会为您提供可重用的服务实例池。会话状态也不在工作进程之间共享。从你的问题来看,你是否正在使用会话还不清楚。如果您需要会话,请使用PerSession。如果不是,请使用PerCall。 – ErnieL 2013-05-01 16:15:11