【发布时间】:2019-05-30 21:55:37
【问题描述】:
最初我使用以下方法发送大量 URL:
for (...) {
using (var client = new HttpClient()) {
client.GetAsync(url);
}
}
原来是wrong way 使用HttpClient,因为.Dispose 将连接留在另一端,从而浪费服务器资源。建议的解决方法是使用 httpClient 的共享副本:
var client = new HttpClient();
for (...) {
client.GetAsync(url);
}
这种方法存在更严重的问题。如果您的目标 url 在负载均衡器后面,httpClient 会与它被路由到的第一个盒子建立连接,然后每次点击都会转到该盒子,而忽略网络场的其余部分。
那么在不浪费连接另一端资源并且能够利用整个网络农场的方式使用 HttpClient 的正确方法是什么?
【问题讨论】:
-
也许初始化几个
HttpClient对象并让它们并行处理自己的负载“块”。否则,您实际上正在做的正是keep-alive被发明用来防止的事情。 -
调查
HttpClientFactory;它使用 HttpClients 池并仅在 DNS 解析为相同 IP 时才重用连接。 Josef Ottosson 有一个good introduction。 -
@DourHighArch 不确定这是否可行,因为所有 URL 都是 foo.com/productid={xxxxx} 的变体,所以它会将其解析为相同的 IP。
-
连接似乎从未中断,因为它没有中断,至少在连接超时之前,通过保持活动状态。如果愿意,可以将 HTTP 标头
Connection设置为close(see here),但这一点都不理想,因为为每个请求创建新连接的开销很可能比绕过任何负载均衡器更糟糕。使用一个 HttpClient(如您的问题)完成所有工作,并行使用多个 HttpClient,或使用 Dour 的解决方案都应该足够有效。 -
没有真正最快或最安全的方法,因为它完全取决于目标。如果服务器使用循环 DNS 或类似的东西,其中客户端是负载平衡的主要因素,请使用 Dour 的解决方案。如果是服务器是负载均衡的首要因素,那么对所有请求使用同一个 HttpClient 是最安全的,使用多个并行是最快的。