実験のために、VS2012で.NET4.5を使用して単純な「HelloWorld」WCFサービスとクライアントを作成しました。サーバーはコンソールアプリケーションでホストされ、net.tcpバインディングを使用します。非同期リクエストのバースト(合計700リクエスト)をサーバーに送信するクライアントコードを作成しました。サービスの信頼できるセッション機能をオンにするまで、すべてがうまくいきました。オンにした後、サービスの実行が突然非常に遅くなり、700の要求を完了するのに私のマシンでほぼ1分かかりました。同時実行パラメーターとスロットルパラメーター(以下を参照)を微調整しようとしましたが、役に立ちませんでした。
なぜこれが起こるのか誰かが知っていますか?これを回避する方法はありますか?
信頼性の高いセッション機能をオフにした場合、またはサービス呼び出しを同期させた場合、速度低下は発生しませんでした。したがって、WCFがWS-ReliableMessagingモードで保留中のリクエストを処理する方法に関連している可能性があると思います。
編集:これは、netTcpBindingをwsHttpBindingに変更したときにも発生しませんでした。この場合、wsHttpBindingはnetTcpBindingよりもはるかに高速であるため、これは非常に奇妙です。
編集:サーバー側でPerfmon.exeを実行すると、上記の場合、「スレッド数」が8から100を超えて徐々に増加することがわかります。
編集:私のPC(ローカルネットワーク)で測定されたスループット。ケース1のパフォーマンスは非常に遅く、実際には役に立たないことがわかります。
- 非同期+NetTcpBinding/信頼性の高いスループット->約 14コール/秒(70ミリ秒/コール)
- 非同期+WsHttp/信頼できるスループット->7957呼び出し/秒(0.12ミリ秒/呼び出し)
- 同期+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>