【问题标题】:Why do I have a .NET Core API performance issue using IHttpClientFactory when ramping up users?为什么在增加用户时使用 IHttpClientFactory 会出现 .NET Core API 性能问题?
【发布时间】:2021-10-09 20:32:08
【问题描述】:

我有一个 .NET Core WebAPI,我的 React UI 正在调用它来验证用户。它为此调用了第 3 方 API。一切正常,但我们已经开始对其进行性能测试,当我们增加尝试同时登录的用户时,它的扩展性不好。 (耗时 30 秒)

我们调用的第 3 方 API 表示它们以毫秒为单位做出响应。

我的 API 托管在 AWS 上的 Kubernetes 容器中。我已将 AWS X-ray 添加到代码中以尝试获取更多信息,但我不确定如何解释结果。

代码非常简单 - 这是来自 MyAuthenticationProvider 类的 sn-p(构造函数采用指标收集器(用于 AWS X-Ray 和用于进行调用的 securityProvider http 客户端)

        metricCollector.StartCollection("Stage 1");
        HttpResponseMessage response = await securityProvider.SendAsync(requestMessage);
        metricCollector.EndCollection();

上述代码的 X-Ray 图像是:

X-Ray 是否显示该 API 确实等待 30 多秒才能返回响应,我应该联系该公司进行进一步调查,即使他们告诉我所有流量也在毫秒。

或者是我在 Startup.cs 的 MyAuthProvider 类中定义的 http 客户端在并发用户增加时无法正确扩展?

这是 Startup.cs 中的代码

      services.AddTransient<IMyAuthenticationProvider>(ctx =>
        {
            IHttpClientFactory clientFactory = ctx.GetRequiredService<IHttpClientFactory>();
            return new MyAuthenticationProvider(
                clientFactory.CreateClient("3RDPARTYAUTHCLIENT"),
                ctx.GetService<IMetricCollector>());
        });

我要提高性能的另一件事是引入 Redis 来缓存其中一些响应,因为它们会为不同的操作多次调用但结果将是相同的

【问题讨论】:

  • 需要注意的一点是HttpClient,默认情况下,只允许向给定端点发送类似 6 个并发请求。因此,如果您的负载超过 6 个请求/(下游 API 响应的时间),它们将开始备份。您可以增加并发 HTTP 请求的数量(例如,请参阅here
  • @RB。 - 感谢链接 - 在这里阅读 - docs.microsoft.com/en-us/dotnet/framework/network-programming/… - 说 ServicePoint 在 .NET Core 5 中被认为是旧版?我不知道这是否意味着它应该在里面解决
  • 我想我可以在这里设置它 - docs.microsoft.com/en-us/dotnet/api/…
  • MyAuthenticationProvider 的生命周期是什么?控制器是否每次都在构造它并调用它?将其注册为瞬态的任何理由?

标签: c# performance asp.net-core .net-core aws-xray


【解决方案1】:

虽然您只创建了 1 个名为 HttpClient,但您已将 IMyAuthenticationProvider 的服务生命周期设置为 transient

这意味着,通过创建IMyAuthenticationProvider 实例每次都需要一个HttpClient,您基本上失去了单个HttpClient 的大部分好处 strong>(在最好的情况下,这将与每个客户端请求同义,但不要误认为是作用域服务)。

这可能会大大降低您的应用程序的速度,并且可能是应用程序扩展性能不佳的原因。

您试图清楚地使用单个 HttpClient,它通常是 static 或包装为单例类中的非静态实例。并且仍然是a good solution for short-lived console applications 等。但是在这种情况下,我允许IHttpClientFactory 解析客户端。

ASP.NET Core 中 IHttpClientFactory 的主要目标是确保正确创建 HttpClient 实例(taking into account things like DNS changes 单个 HttpClient 实例无法处理),同时消除套接字耗尽。

IHttpClientFactory 注入的 HttpClient 实例有一个 transient lifetime(文档是冲突的,并且出于某种荒谬的原因提到了瞬态 2x 和作用域 1x),所以我会 IMyAuthenticationProvider 的生命周期设置为作用域使其尽可能地被重复使用

不应使用运行时间较长的单例 IHttpClientFactory,在这种情况下,不应使用注入的生命周期较短的作用域 HttpClient

MSFT:

不要从单例中解析作用域服务,并注意不要间接这样做

虽然注入的HttpClient 对象是瞬态的,但使用IHttpClientFactory 可以合并HttpMessageHandler 对象,这些对象可以并且将被多个HttpClient 实例重用。

试试:

services.AddHttpClient<IMyAuthenticationProvider, MyAuthenticationProvider>();
services.AddHttpClient<IMetricCollector, MetricCollector>();
...

services.AddScoped<IMyAuthenticationProvider, MyAuthenticationProvider>();
public class MyAuthenticationProvider : IMyAuthenticationProvider
{
  private readonly HttpClient _httpClient;

  public MyAuthenticationProvider(HttpClient httpClient)
  {
      _httpClient = httpClient;
  }

  ...
}

【讨论】:

  • 我试试看
  • @Ctrl_Alt_Defeat 让我知道 :)
  • @Ctrl_Alt_Defeat 这是对您的问题进行排序还是其他问题?我很好奇! :)
  • 我还没有按照你的建议进行重构。我将在更新 MaxConnectionsPerServer 属性的情况下运行另一个压力测试
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
  • 2021-12-03
相关资源
最近更新 更多