2017-11-16 3 views
0

私は以下の問題を抱えています。 IISサーバーと同じ地域にあるサーバーに約500msごとにリクエストを送信する.Netモジュールで作業しています。 これらの要求のほとんど(約99%)は、処理するのに約1〜3msかかる。しかし、これらの要求の一部はタイムアウトしています(私はWebRequest.Timeoutを150msに設定しました、それは重要です)。.Netモジュールの奇妙なタイムアウトの問題

2奇妙なことがあります:

  • まず、タイムアウト要求が他の要求が雷
  • として迅速ですと奇妙である私が無限にタイムアウトを設定した場合に実行する〜について180msを取るだろうWebExceptionをキャッチすると、を150msに設定していたのに対して、私はWebRequest.GetResponse()と呼び出されてから例外がキャッチされるまでの間に〜350msを測定します。パフォーマンスのこのギャップは本当に私たちのための問題であり、それはこれが私が働いているレガシーコードです

が起こっている理由を私は理解していない:

ApiResult IApiService.Request(IConnectorRequest request) 
{ 
    long timestamp = 0; 
    DebugStream debug = null; 

    try 
    { 
     var dictionary = CollectData(request); 

     //TODO:May be include some ServicePoint information. 
     //APIConnectionState=Reused 

     // Sending request to the API ////////////////////////////////////////////////////// 
     var http = CreateRequest(); 

     Stream stream; 
     using (stream = http.GetRequestStream()) 
     { 
      if (_Log.IsDebug) 
      { 
       stream = debug = new DebugStream(stream, _Encoding); 
      } 

      dictionary.WriteForm(stream, _Encoding); 
     } 

     if (debug != null) 
     { 
      _Log.Debug("WebRequestApiService.Request({0:N}): {1}", request.Id, debug.Data); 
     } 

     // Start request and fix timestamp before execution. 
     timestamp = Stopwatch.GetTimestamp(); 
     var response = http.GetResponse() as HttpWebResponse; 
     // (Stopwatch.GetTimestamp() - timestamp)/TimeSpan.TicksPerMillisecond => ~2ms 

     if (response == null) 
     { 
      const string message = "Response is not HttpWebResponse"; 
      _Log.Warning("WebRequestApiService.Request({0:N}): {1}", request.Id, message); 

      return ApiResult.Failure(message); 
     } 
     response.GetRequestHeaders(); 
     return new ApiResult() 
     { 
      StatusCode = (int)response.StatusCode, 
      Description = response.StatusDescription, 
      DataDomeStatus = response.GetStatusHeader(), 
      Headers = response.GetHeaders() 
     }; 
    } 
    catch (WebException we) 
    { 
     var errorMessage = string.Empty; 
     var response = we.Response as HttpWebResponse; 
     Exception e; 

     if (response != null) 
     { 
      errorMessage = response.GetText(out e); 

      if (response.StatusCode == HttpStatusCode.Forbidden) 
      { 
       return new ApiResult() 
       { 
        StatusCode = (int)response.StatusCode, 
        Description = response.StatusDescription, 
        DataDomeStatus = response.GetStatusHeader(), 
        Headers = response.GetHeaders(), 
        Content = errorMessage 
       }; 
      } 

      if (errorMessage == null) 
      { 
       _Log.Warning("WebRequestApiService.Request({0}): Problem getting response {1}", request.Id, e); 
      } 
     } 

     // (Stopwatch.GetTimestamp() - timestamp)/TimeSpan.TicksPerMillisecond => ~350ms 
     _Log.Warning(
      "WebRequestApiService.Request({0}): Message={1}\nTimeout={2}\nError=\n{3}\n\nRequest=\n{4}\n\nAPI=\n{5}\n", 
      request.Id, 
      errorMessage, 
      (Stopwatch.GetTimestamp() - timestamp)/TimeSpan.TicksPerMillisecond, 
      we, 
      request.Dump(), 
      debug != null ? debug.Data : "NULL" 
     ); 

     return ApiResult.Failure(errorMessage); 
    } 
    catch (Exception e) 
    { 
     _Log.Warning(
      "WebRequestApiService.Request({0}): Timeout={1}\nError=\n{2}\n\nRequest=\n{3}\n\nAPI=\n{4}\n", 
      request.Id, 
      (Stopwatch.GetTimestamp() - timestamp)/TimeSpan.TicksPerMillisecond, 
      e, 
      request.Dump(), 
      debug != null ? debug.Data : "NULL" 
     ); 

     return ApiResult.Failure(e.Message); 
    } 
} 

そして、これが使用される方法であります私たちは、HttpWebRequestを作成します。

private HttpWebRequest CreateRequest() 
{ 
    var http = WebRequest.Create(_uri) as HttpWebRequest; 

    if (http == null) 
    { 
     throw new NotImplementedException(); 
    } 

    // Disable proxy (if node proxy configuration in config file). Otherwise the first 
    // request will be slowed down due the proxy auto-detection. 
    if (_noProxy) 
    { 
     http.Proxy = null; 
    } 

    // Configure timeout. 150ms in our case 
    http.Timeout = _timeout; 

    // Force connection to be keep-alive. 
    http.KeepAlive = true; 

    // Disable caching. 
    http.CachePolicy = _cachePolicy; 

    // Basic request fields 
    http.Method = "POST"; 
    http.ContentType = "application/x-www-form-urlencoded"; 
    http.UserAgent = null; 

    // If auto redirect is allowed, then we can't catch redirect response from API server. 
    http.AllowAutoRedirect = false; 

    return http; 
} 

誰かがWebRequestクラスの振る舞いを知っていて、それはいくつかの重いスローダウンを持つことができますなぜ私が経験していていますか?タイムアウトを150msに設定すると、例外が350msでキャッチされる(これはパフォーマンスの重い問題です)。

私は本当にC#と.NETでより多くの経験を積んだ人からいくつかの助けのように、私はこの世界に新たなんだと思いますので、顧客は制約が

が問題の可能性が高いDNSで、事前

答えて

0

にありがとう要求してきましたクエリ関連。 documentationTimeout状態の:

Aドメインネームシステム(DNS)クエリが や時間を返すために15秒かかることがあります。要求に の解決を必要とするホスト名が含まれていて、Timeoutを15秒未満の値に設定した場合は、 タイムアウトを示すWebExceptionがスローされる前に、 が15秒以上かかることがあります。

+0

DNSルックアップには関係しません。私は自分のアイデアを検証しようとしました。.NetアプリケーションからDNSルックアップのトラフィックを盗聴しました。その結果、10分間と1000リクエスト以上で4回のDNS検索が行われ、50回のタイムアウトが発生しました。また、タイムアウトの日付とDNSルックアップの日付が一致しません:( –