.Net模块WebRequests上出现奇怪的超时问题

时间:2017-11-16 11:18:58

标签: c# asp.net asp.net-web-api timeout dotnet-httpclient

我有以下问题: 我正在研究一个.Net模块,该模块每隔约500ms向位于与IIS服务器相同区域的服务器发送请求。 大多数这些要求(约99%)需要大约1~3ms才能得到治疗。但是,其中一些请求超时(我将WebRequest.Timeout设置为150毫秒,这很重要。)

有两件奇怪的事情:

  • 首先,如果我将超时设置为无限,超时请求将需要大约180ms才能执行,这很奇怪,因为其他请求快速闪电
  • 当捕获WebException时,我在调用WebRequest.GetResponse()和捕获异常的那一刻之间测量~350ms,而我将WebRequet.Timeout设置为150ms。这种性能差距对我们来说确实是一个问题,我不明白为什么会发生这种情况

这是我正在处理的遗留代码:

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的行为以及为什么它会像我一样经历一些重大的减速?为什么将超时设置为150毫秒会导致异常被捕获到350毫秒(这对我们来说是一个糟糕的性能问题)?

我真的很喜欢C#和.Net经验丰富的人的帮助,因为我是这个世界的新手并且有客户请求限制

提前谢谢

1 个答案:

答案 0 :(得分:0)

问题可能与DNS查询有关。 Timeout状态的documentation

  

域名系统(DNS)查询最多可能需要15秒才能返回   或者超时。如果您的请求包含需要的主机名   分辨率,你可以将Timeout设置为小于15秒的值   在抛出WebException之前需要15秒或更长时间来指示a   你的请求超时。