1

我们正在 IIS 上设计具有以下特征的 WCF Web 服务:

  • 对象创建相对繁重(大约需要 500 毫秒),因为它涉及写入文件
  • 创建对象后无需保留任何状态
  • 来自客户端的每个呼叫平均需要 150 - 200 毫秒。此调用涉及向另一台服务器发送 UDP 请求并接收响应。
  • 我们预计大约有 30 个同时存在的客户。它可能会增长到 50 个客户。在最坏的情况下(50 个客户端),我们将需要一个包含 10 个对象实例的池来处理此负载。

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

4

1 回答 1

3

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

如果您在实现中使用依赖注入容器,例如Castle WindsorStructureMap或 MS Enterprise Library 的Unity,那么您可以将容器的现有 IInstanceProvider 与池化生活方式一起使用。所有这些容器都是合理的(尽管我个人没有太多让它们管理对象池的经验)。

我个人选择的容器是温莎城堡。在这种情况下,您将使用 Windsor 的WCF 集成设施共享生活方式

这是一个使用 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();
            }
        }
    }
}

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

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
于 2013-04-21T21:09:37.893 回答