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 Integration Facilityプールされたライフスタイルを使用します。

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 に答える