4

実験のために、VS2012で.NET4.5を使用して単純な「HelloWorld」WCFサービスとクライアントを作成しました。サーバーはコンソールアプリケーションでホストされ、net.tcpバインディングを使用します。非同期リクエストのバースト(合計700リクエスト)をサーバーに送信するクライアントコードを作成しました。サービスの信頼できるセッション機能をオンにするまで、すべてがうまくいきました。オンにした後、サービスの実行が突然非常に遅くなり、700の要求を完了するのに私のマシンでほぼ1分かかりました。同時実行パラメーターとスロットルパラメーター(以下を参照)を微調整しようとしましたが、役に立ちませんでした。

なぜこれが起こるのか誰かが知っていますか?これを回避する方法はありますか?

信頼性の高いセッション機能をオフにした場合、またはサービス呼び出しを同期させた場合、速度低下は発生しませんでした。したがって、WCFがWS-ReliableMessagingモードで保留中のリクエストを処理する方法に関連している可能性があると思います。

編集:これは、netTcpBindingをwsHttpBindingに変更したときにも発生しませんでした。この場合、wsHttpBindingはnetTcpBindingよりもはるかに高速であるため、これは非常に奇妙です。

編集:サーバー側でPerfmon.exeを実行すると、上記の場合、「スレッド数」が8から100を超えて徐々に増加することがわかります。

編集:私のPC(ローカルネットワーク)で測定されたスループット。ケース1のパフォーマンスは非常に遅く、実際には役に立たないことがわかります。

  1. 非同期+NetTcpBinding/信頼性の高いスループット->約 14コール/秒(70ミリ秒/コール)
  2. 非同期+WsHttp/信頼できるスループット->7957呼び出し/秒(0.12ミリ秒/呼び出し)
  3. 同期+NetTcpBinding/信頼性の高いスループット->3986呼び出し/秒(0.25ミリ秒/呼び出し)

以下は、実験で使用したサーバーとクライアントのコードと構成です。

サーバ:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.ServiceModel;
using System.ServiceModel.Description;

[ServiceContract]
public interface IHelloService
{
    [OperationContract(IsOneWay=false)]
    string SayHello(string name);
}

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode=InstanceContextMode.PerSession)]
public class HelloService : IHelloService
{
    public string SayHello(string name) {
        String s = string.Format("Hello {0}", name); 
        return s; 
    }
}

namespace WcfServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("net.tcp://localhost:8080/hello");
            using (ServiceHost host = new ServiceHost(typeof(HelloService), baseAddress)){
                // Open and listen
                host.Open();
                Console.WriteLine("The service is ready at {0}", baseAddress);
                Console.WriteLine("Press <Enter> to stop the service.");
                Console.ReadLine();
                // Close the ServiceHost.
                host.Close();
            }
        }
    }
}

クライアント:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.ServiceModel;
using WcfClient.WcfServer;

namespace WcfClient
{
    class Program
    {
        static async Task PrintNameAsync(HelloServiceClient client, int cnt) {
            string s = await client.SayHelloAsync(string.Format("-- {0} --", cnt));
            Console.WriteLine(s);
        }

        static void Main(string[] args)
        {
            HelloServiceClient client = new HelloServiceClient("HelloService", "net.tcp://10.20.61.13:8080/hello");
            List<Task> tasks = new List<Task>();
            for(int i=0; i < 700; i++){
                Task t = PrintNameAsync(client, i);
                tasks.Add(t);
            }
            Task.WhenAll(tasks).Wait();
            client.Close();
        }
    }
}

サーバーのApp.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="HelloServiceBinding">
                    <reliableSession ordered="true" enabled="true" />
                    <security mode="None" />
                </binding>
            </netTcpBinding>
        </bindings>
        <behaviors>
            <serviceBehaviors>
                <behavior name="HelloServiceBehavior">
                    <serviceMetadata policyVersion="Policy15" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceThrottling maxConcurrentCalls="1000" maxConcurrentSessions="1000"
                        maxConcurrentInstances="1000" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="HelloServiceBehavior" name="HelloService">
                <endpoint address="net.tcp://localhost:8080/hello" binding="netTcpBinding"
                    bindingConfiguration="HelloServiceBinding" name="HelloService" contract="IHelloService" />
                <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
            </service>
        </services>
    </system.serviceModel>
</configuration>

クライアントのApp.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="HelloServiceBinding" sendTimeout="00:01:00">
                    <reliableSession enabled="true" />
                    <security mode="None" />
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://localhost:8080/hello" binding="netTcpBinding"
                bindingConfiguration="HelloServiceBinding" contract="WcfServer.IHelloService"
                name="HelloService">
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>
4

3 に答える 3

2

以下のリンクから、問題の部分的な回避策を見つけました。

回避策 (WorkerThreadPoolBehavior を使用) を使用すると、測定されたスループットは次のようになります。

  1. Async + NetTcpBinding/信頼できるスループット -> 474 コール/秒 (2.1 ミリ秒/コール) ... 改善されましたが、満足のいくものではありませんでした
  2. Async + WsHttp/信頼できるスループット -> 7856 コール/秒 (0.13 ミリ秒/コール) ... 変化なし
  3. 同期 + NetTcpBinding/信頼できるスループット -> 2110 コール/秒 0.47 ミリ秒/コール) ... 劣化

上記のケース 1 は、70 ミリ秒/コールから大幅に改善されていることに注意してください。ただし、ケース 2 からはまだ遅れています。ケース 3 では、WorkerThreadPool の動作を導入すると、0.25 ms/call から 0.47 ms/call にパフォーマンスが低下します。

于 2012-10-30T03:03:59.417 に答える
2

これを見て...

" MaxTransferWindowSize の設定

Windows Communication Foundation (WCF) の信頼できるセッションでは、転送ウィンドウを使用して、クライアントとサービスでメッセージを保持します。構成可能なプロパティMaxTransferWindowSizeは、転送ウィンドウが保持できるメッセージの数を示します。

送信側では、これは確認応答を待っている間に転送ウィンドウが保持できるメッセージの数を示します。受信側では、サービスのためにバッファするメッセージの数を示します...」

ソース「MSDN: 信頼できるセッションのベスト プラクティス」: http://msdn.microsoft.com/en-us/library/ms733795.aspx

于 2013-07-19T15:23:46.830 に答える
1

メッセージを非同期で送信していますが、ReliableSessionBindingElementでordered="true"になっています。これは意味がありません。シナリオにとってより意味があるため、orderedをfalseに設定します。ReliableMessagingは、すべての応答メッセージにSequenceAcknowledgementを追加するため、パフォーマンスが低下します。また、CreateSequence/CreateSequenceResponseおよびCloseSequence/CloseSequenceResponseのオーバーヘッドが追加され、セッションの開始時と終了時にTerminateSequence/TerminateSequenceResponseメッセージ交換が行われます。

于 2012-10-23T16:45:36.997 に答える