WebApi上的HttpClient非常缓慢

3
我正在使用ASP.NET WebApi(ApiController)来实现我的应用程序的代理,并使用HttpClient在请求中加入授权头。虽然它可以运行,但速度非常慢。下面是主要代码、全局初始化(包括DefaultConnectionLimit)和web.config相关部分。
正如您所看到的,我已经在实际请求中使用了静态/共享HttpClient对象,没有代理,并且在请求中使用了HttpCompletionOption.ResponseHeadersRead。这个WebApi端点被并行调用,可以正常工作。
整个代码运行速度足够快,但由于我使用了ResponseHeadersRead异步方式,因此HttpRequestMessage被返回后,其余部分仍需下载并直接流式传输到客户端/调用方。
以下是一个视频展示问题:链接
public class ProxyController : ApiController
{
  private const string BASE_URL = "https://developer.api.autodesk.com";
  private const string PROXY_ROUTE = "api/viewerproxy/";


  // HttpClient has been designed to be re-used for multiple calls. Even across multiple threads. 
  // https://dev59.com/xGEh5IYBdhLWcg3wTB_2
  private static HttpClient _httpClient;

  [HttpGet]
  [Route(PROXY_ROUTE + "{*.}")]
  public async Task<HttpResponseMessage> Get()
  {
    if (_httpClient == null)
    {
      _httpClient = new HttpClient(new HttpClientHandler() 
         {
            UseProxy = false,
            Proxy = null
         });
      _httpClient.BaseAddress = new Uri(BASE_URL);
    }

    string url = Request.RequestUri.AbsolutePath.Replace(PROXY_ROUTE, string.Empty);
    string absoluteUrl = url + Request.RequestUri.Query;

    try
    {
      HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, absoluteUrl);
      request.Headers.Add("Authorization", "Bearer " + AccessToken);

      HttpResponseMessage response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

      return response;
    }
    catch (Exception e)
    {
      return new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);
    }
  }
}

虽然我不认为全局.asax是连接限制的问题,因为所有请求都被处理了,但只是太慢了...

public class Global : System.Web.HttpApplication
{
  protected void Application_Start(object sender, EventArgs e)
  {
    GlobalConfiguration.Configure(Config.WebApiConfig.Register);

    ServicePointManager.UseNagleAlgorithm = true;
    ServicePointManager.Expect100Continue = false;
    ServicePointManager.CheckCertificateRevocationList = true;
    ServicePointManager.DefaultConnectionLimit = int.MaxValue;
  }
}

以下是 Web.Config 的一部分内容:

 <system.web>
    <compilation debug="true" targetFramework="4.6" />
    <httpRuntime targetFramework="4.6" maxRequestLength="2097151" requestLengthDiskThreshold="16384" requestPathInvalidCharacters="&lt;,&gt;,*,%,&amp;,\,?" />
  </system.web>

你尝试过对你的应用程序进行性能分析吗?它的哪个部分看起来比较慢? - Andrii Litvinov
由于我在SendAsync调用中使用了ResponseHeadersRead,整个代码运行并且HttpRequestMessage非常快地返回,但是HttpClient继续直接下载并发送给客户端,而这个“流”非常缓慢。 - Augusto Goncalves
你的代理和下游服务之间的通信可能很慢吗?另外,如果你尝试缓冲响应(删除 HttpCompletionOption.ResponseHeadersRead),会怎样呢?它是单个请求慢还是在负载下慢? - Andrii Litvinov
谢谢分享这个视频,看起来在处理请求时CPU利用率达到了100%。所以也许CPU是瓶颈? - Andrii Litvinov
不太可能,除非我做了什么很糟糕的事情。这段代码大约每次处理5个请求,每个请求大小约为1MB... - Augusto Goncalves
显示剩余4条评论
2个回答

1
通过移除 web.config 文件中的 <system.diagnostics> 部分解决了问题。似乎这部分内容导致输出过多,从而减慢了所有 HttpClient 请求的速度。
顺便提一下,以下是我使用并导致所有 HttpClient.SendAsync 调用变慢的代码。但这对于跟踪连接问题非常有用 :-)
<system.diagnostics>
  <sources>
    <source name="System.Net" tracemode="protocolonly" maxdatasize="1024">
      <listeners>
        <add name="System.Net"/>
      </listeners>
    </source>
    <source name="System.Net.Cache">
      <listeners>
        <add name="System.Net"/>
      </listeners>
    </source>
    <source name="System.Net.Http">
      <listeners>
        <add name="System.Net"/>
      </listeners>
    </source>
  </sources>
  <switches>
    <add name="System.Net" value="Verbose"/>
    <add name="System.Net.Cache" value="Verbose"/>
    <add name="System.Net.Http" value="Verbose"/>
    <add name="System.Net.Sockets" value="Verbose"/>
    <add name="System.Net.WebSockets" value="Verbose"/>
  </switches>
  <sharedListeners>
    <add name="System.Net"
      type="System.Diagnostics.TextWriterTraceListener"
      initializeData="network.log"
    />
  </sharedListeners>
  <trace autoflush="true"/>
</system.diagnostics>

0
5年后,我遇到了同样的问题。我通过在VS项目的属性设置中删除任何分析器来解决它:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接