在WebAPI客户机中每次调用创建一个新的HttpClient的开销是多少?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (21)

HttpClientWebAPI客户端的生命周期应该是什么?多次调用 有一个实例会更好HttpClient吗?

创建和处理HttpClient每个请求的开销是多少,如下面的示例(摘自http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from- a-net-client):

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost:9000/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    // New code:
    HttpResponseMessage response = await client.GetAsync("api/products/1");
    if (response.IsSuccessStatusCode)
    {
        Product product = await response.Content.ReadAsAsync>Product>();
        Console.WriteLine("{0}\t${1}\t{2}", product.Name, product.Price, product.Category);
    }
}
提问于
用户回答回答于

HttpClient已被设计为重复使用多个呼叫。即使跨多个线程。该HttpClientHandler有凭据和意在调用被重新使用的饼干。拥有一个新HttpClient实例需要重新设置所有这些东西。另外,该DefaultRequestHeaders属性包含用于多次调用的属性。不得不在每个请求上重置这些值都会使这一点失败。

另一个主要好处HttpClient是能够添加HttpMessageHandlers到请求/响应管道中以应用交叉问题。这些可以用于记录,审计,限制,重定向处理,离线处理,捕获指标。各种不同的东西。如果每个请求都创建一个新的HttpClient,那么需要在每个请求上设置所有这些消息处理程序,并且还需要提供在这些处理程序的请求之间共享的任何应用程序级别状态。

您使用这些功能HttpClient的次数越多,您会看到重复使用现有实例的意义越强。

然而,我认为最大的问题是,当一个HttpClient类被处置时,它会处理HttpClientHandler,然后强制关闭TCP/IP由其管理的连接池中的连接ServicePointManager。这意味着每个请求都HttpClient需要重新建立一个新TCP/IP连接。

从我的测试中,在局域网上使用普通HTTP,性能命中率可以忽略不计。我怀疑这是因为有一个潜在的TCP保持连接,即使在HttpClientHandler尝试关闭连接时也保持连接处于打开状态。

在通过互联网的请求中,我看到了另一个故事。由于每次都必须重新打开请求,因此我看到了40%的性能问题。

我怀疑HTTPS连接的打击会更糟。

我的建议是在你连接到的每个不同的API的应用程序的生命周期中保留一个HttpClient的实例

用户回答回答于

如果你想让你的应用程序扩展,差异是巨大的!根据负载的不同,你会看到非常不同的性能数字。正如Darrel Miller提到的那样,HttpClient被设计为跨请求重用。BCL团队的编写人员证实了这一点。

我最近的一个项目是帮助一家非常大型的知名在线电脑零售商扩展黑色星期五/假日交通以满足一些新系统的需求。我们遇到了有关使用HttpClient的一些性能问题。由于它实现了IDisposable,开发人员通过创建实例并将其放置在using()语句中来完成通常要做的事情。一旦我们开始加载测试,应用程序就会让服务器瘫痪 - 是的,服务器不仅仅是应用程序。原因是每个HttpClient实例都在服务器上打开一个端口。由于GC的非确定性终结和你正在使用跨越多个OSI层的计算机资源的事实,关闭网络端口可能需要一段时间。实际上Windows操作系统本身可能需要长达20秒才能关闭一个端口(每个微软)。我们打开端口的速度比它们可能被关闭得更快 - 服务器端口耗尽,导致CPU达到100%。我的修复是将HttpClient更改为解决问题的静态实例。是的,这是一种可随意使用的资源,但任何开销都会大大超过性能差异。我鼓励你做一些负载测试,看看你的应用程序的行为。

你也可以通过https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client查看WebAPI指导页面的文档和示例

请特别注意这一呼吁:

HttpClient旨在实例化一次并在应用程序的整个生命周期中重新使用。特别是在服务器应用程序中,为每个请求创建一个新的HttpClient实例将耗尽大负载下可用的套接字数量。这将导致SocketException错误。

如果你发现需要使用HttpClient具有不同标题,基地址等的静态内容,则需要执行的操作是HttpRequestMessage手动创建并在其上设置这些值HttpRequestMessage。然后,使用HttpClient:SendAsync(HttpRequestMessage requestMessage, ...)

扫码关注云+社区