1

C# 4.0 (すぐには 4.5 にアップグレードできません) と WCF を使用しています。私はサーバーを制御しておらず、使用されているコードやテクノロジーを見ることができないことに注意してください。この問題は、さまざまな人が作成したさまざまなサーバーで発生します。

サーバーごとに 1 つずつ、多くのサーバー (10 としましょう) にできるだけ多くの要求を送信します。1 秒あたり 2 ~ 30 のリクエストが発生します。30 秒から 5 分の間に、 TimeoutException が発生します。

exception   {"The HTTP request to 'http://xx.xx.xx.xx/service/test_service' has exceeded the allotted timeout of 00:02:10. The time allotted to this operation may have been a portion of a longer timeout."}   System.Exception {System.TimeoutException}.

Stack Trace :
Server stack trace: 
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult     result)
   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeEndService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,  IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Device.EndTest(IAsyncResult result)
   at DeviceClient.EndTest(IAsyncResult result) in ...
   at TestAsync(IAsyncResult ar) in ...

InnerException は次のとおりです。

[System.Net.WebException]   {"The request was aborted: The request was canceled."}  System.Net.WebException
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)

Wireshark は、接続を開いていない (SYN がない) ことを教えてくれます。したがって、これはクライアントの問題である必要があります。TCPView に多くの TIME_WAIT 接続があります

同期呼び出しの使用は機能していますが、不可能です。

次のコード例では、サーバーごとに 1 つのメソッド呼び出しがあることに注意してください。(私の場合、10個の同時TestAsync)

(実際のプロジェクトでは、セマフォの代わりに CCR を使用しますが、結果は同じです)

private void AsyncTest()
{   
    //GetServiceObject Will add custom bindings and more..
    Client client = ClientBuilder.GetServiceObject();

    while (true)
    {
         Semaphore semaphore = new Semaphore(0,1);
         client.BeginTest(BeginTestCallback, new AsyncState
         {
             Client = client,
             Semaphore = semaphore
         });

         semaphore.WaitOne();   
    }   
 }

private void BeginTestCallback(IAsyncResult asyncResult)
{
    try
    {
        AsyncState state = asyncResult.AsyncState as AsyncState;

        Client client = state.Client;
        Semaphore semaphore = state.Semaphore;

        Client.EndTest(asyncResult);    

        semaphore.Release();
    }
    catch (Exception e)
    {
        //Will catch the exception here because of Client.EndTest(asyncResult)
        Debug.Assert(false, e.Message);
    }
}

で試しました

ServicePointManager.DefaultConnectionLimit = 200;
ServicePointManager.MaxServicePointIdleTime = 2000;

いくつかの投稿が示唆したように、成功しませんでした。

オープン、送信、受信、クローズのタイムアウトを本当に高く設定しても、同じ例外が発生します。WCF は、リクエストの送信時に「スタック」しているようです。サーバーは引き続き他の要求に正しく応答します。

アイデアはありますか?

また、これを行うと (while(true) の代わりに Callback で BeginTest を実行)、例外が発生することはありません?!?!

private void AsyncTest()
{
    //GetServiceObject Will add custom bindings and more..
    Client client = ClientBuilder.GetServiceObject();
    try
    {
        client.BeginTest(BeginTestCallback, new AsyncState
        {
            Client  = client            
        });
    }
    catch (Exception e)
    {
        Debug.Assert(false, e.Message);
    }
}

private void BeginTestCallback(IAsyncResult asyncResult)
{
    try
    {
        AsyncState state = asyncResult.AsyncState as AsyncState;        

        state.Client.EndTest(asyncResult);

        state.Client.BeginTest(BeginTestCallback, state);
    }
    catch (Exception e)
    {
        //No Exception here
        Debug.Assert(false, e.Message);
    }
}
4

1 に答える 1

1

さらにテストを重ねた結果、開始/終了メカニズムが同じスレッド プールで実行されていない場合、この動作がランダムに行われることがわかりました。

最初のケースでは、"AsyncTest" が ThreadStart と Thread を使用して新しいスレッド内で生成されました。2 番目のケースでは、最初の「開始」のみが専用スレッドで呼び出され、問題がランダムに発生するため、最初の要求で例外が発生する可能性がわずかにあります。他の「開始」は、.net ThreadPool で行われます。

最初のケースで Task.Factory.StartNew(() => AsyncTest()) を使用すると、問題はなくなりました。

私の実際のプロジェクトでは、begin/end を呼び出さなければならないまで、すべてを行うために CCR (および CCR スレッドプール) を使用しています。

WCF が別のスレッドプールで呼び出されるのを好まない理由について、より良い説明がある人はいますか?

于 2012-08-31T11:22:09.473 に答える