使用HttpClient发送大量请求的最快且最安全的方法是什么?

4

最初我使用以下方法发送大量的URL:

for (...) {
  using (var client = new HttpClient()) {
    client.GetAsync(url);
  } 
}

原来,这是使用 HttpClient 的错误方式,因为 .Dispose 会使连接保留在另一侧,从而浪费服务器资源。建议的解决方法是使用共享的 httpClient 副本:
var client = new HttpClient();
for (...) {
  client.GetAsync(url);
}

这种方法存在更严重的问题。如果您的目标url在负载均衡器后面,httpClient会与路由到的第一个盒子建立连接,并且每个后续请求都将发送到该盒子,忽略其余web farm中的内容。
那么正确的使用HttpClient的方法是什么呢?它可以避免浪费连接另一端的资源,并能够利用整个web farm?

1
也许可以初始化一对HttpClient对象,让它们独立并行地处理各自的“块”负载。否则,你实际上正在做恰好与keep-alive旨在防止的事情相同。 - Prime
1
调查HttpClientFactory; 它使用一组HttpClients并仅在DNS解析到相同的IP时重用连接。Josef Ottosson有一个很好的介绍 - Dour High Arch
如果网站使用轮询DNS进行负载均衡,则如果正确,Dour的解决方案将是正确的。如果网站使用反向代理作为其负载均衡器,则无论如何都没有关系,请求将由服务器而不是客户端委派。 - Prime
1
似乎连接从未断开,因为它并没有断开,至少直到通过保持活动状态超时。如果您愿意,可以将HTTP头“Connection”设置为“close”(请参见此处),但这绝不是理想的,因为为每个请求创建新连接的开销很可能比绕过任何负载均衡器更糟糕。使用一个HttpClient完成所有工作(如您的问题中所示),并行使用多个HttpClients或使用Dour的解决方案都应该足够有效。 - Prime
1
没有真正的最快或最安全的方法,因为这完全取决于目标。如果服务器使用轮询 DNS 或类似的负载均衡方式,其中客户端是负载均衡的主要因素,请使用 Dour 的解决方案。如果服务器是负载均衡的主要因素,则对所有请求使用相同的 HttpClient 是最安全的,同时并行使用多个 HttpClient 是最快的。 - Prime
显示剩余3条评论
1个回答

1
如果您想使用多个HTTP连接,一个简单的解决方案可能是这样的:
const int size = 12;
var clients = new HttpClient[size];
for (var i = 0; i < size; i++)
{
    clients[i] = new HttpClient();
}

int j = 0;
for (...)
{
    clients[j++%size].GetAsync(url); // todo: handle async correctly
}

如果您正在使用ASP.NET Core应用程序,我建议您考虑使用IHttpClientFactory。如果您不使用IHttpClientFactory,请注意,如果DNS更改在应用程序的生命周期内发生,它将不会反映出来。

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