如何使用 HttpClient 改善慢速 DNS?
How to improve slow DNS with HttpClient?
我有一个针对特定域的请求需要很长时间才能完成:平均 22 秒。请求本身并没有return很多数据。
var httpClient = new HttpClient(); //instantiated at app start and reused
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.somedomain.com");
var result = await httpClient.SendAsync(request); //take a really long time
调试了一下,好像跟DNS有关。如果我 运行 完全相同的请求但用 IP 替换域名,它很快(< 200 毫秒)。
如果我使用相同的 HttpClient
实例第二次 运行 请求,它也很快。但是,如果我 运行 在超过一分钟后发出第二个请求,它又变慢了(可能是因为连接在 1 分钟后自动关闭)。
有什么办法可以改善吗? (例如:确保已解析的 DNS 条目会在缓存中保留很长时间)。另外,为什么使用 HttpClient
时该域的 DNS 速度如此之慢?如果我尝试使用 Chrome 访问该域,它会非常快(即使在刷新 DNS 和清除缓存之后)。使用在线服务对该域进行 DNS 查找也非常快。报告的 TTL 为 60 分钟。
编辑:我尝试增加 ServicePointManager.DnsRefreshTimeout
(默认设置为 2 分钟)。但这并没有帮助。
调用 Dns.GetHostEntry("somedomain.com")
是即时的并且 return 正确的 IP。我不知道为什么 HttpClient
的请求这么慢。
这不仅仅是关于缓存 DNS 查询。如果您为每个请求创建新的客户端,那么在每个请求之前都会进行 TCP 和 HTTP 握手——这会使您的单个请求变慢。这可能是使用“旧”代理的后续请求更快的原因——握手仅在第一次请求之前进行,但不会在第二次请求之前进行。
我发现问题所在:速度慢的域在 DNS 记录中有一个 IPV6 地址。
这可以通过调用这个函数来确认:
Dns.GetHostEntry("somedomain.com")
首先它会尝试使用 IPV6 进行连接。最终,超时发生。然后它尝试 IPV4(并且有效)。这解释了为什么它这么慢。目前我找到的解决方案是通过自己解析域名强制IPV4:
var uri = new Uri("somedomain.com");
var builder = new UriBuilder(uri);
var addresses = await Dns.GetHostAddressesAsync(uri.Host);
builder.Host = addresses
.First(x => x.AddressFamily == AddressFamily.InterNetwork) //IPV4 only
.ToString();
var request = new HttpRequestMessage(HttpMethod.Get, builder.Uri);
request.Host = uri.Host;
也许有更好的方法。我无法使用 SocketsHttpHandler
,因为我坚持使用 .NET Framework 4.5
我有一个针对特定域的请求需要很长时间才能完成:平均 22 秒。请求本身并没有return很多数据。
var httpClient = new HttpClient(); //instantiated at app start and reused
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.somedomain.com");
var result = await httpClient.SendAsync(request); //take a really long time
调试了一下,好像跟DNS有关。如果我 运行 完全相同的请求但用 IP 替换域名,它很快(< 200 毫秒)。
如果我使用相同的 HttpClient
实例第二次 运行 请求,它也很快。但是,如果我 运行 在超过一分钟后发出第二个请求,它又变慢了(可能是因为连接在 1 分钟后自动关闭)。
有什么办法可以改善吗? (例如:确保已解析的 DNS 条目会在缓存中保留很长时间)。另外,为什么使用 HttpClient
时该域的 DNS 速度如此之慢?如果我尝试使用 Chrome 访问该域,它会非常快(即使在刷新 DNS 和清除缓存之后)。使用在线服务对该域进行 DNS 查找也非常快。报告的 TTL 为 60 分钟。
编辑:我尝试增加 ServicePointManager.DnsRefreshTimeout
(默认设置为 2 分钟)。但这并没有帮助。
调用 Dns.GetHostEntry("somedomain.com")
是即时的并且 return 正确的 IP。我不知道为什么 HttpClient
的请求这么慢。
这不仅仅是关于缓存 DNS 查询。如果您为每个请求创建新的客户端,那么在每个请求之前都会进行 TCP 和 HTTP 握手——这会使您的单个请求变慢。这可能是使用“旧”代理的后续请求更快的原因——握手仅在第一次请求之前进行,但不会在第二次请求之前进行。
我发现问题所在:速度慢的域在 DNS 记录中有一个 IPV6 地址。 这可以通过调用这个函数来确认:
Dns.GetHostEntry("somedomain.com")
首先它会尝试使用 IPV6 进行连接。最终,超时发生。然后它尝试 IPV4(并且有效)。这解释了为什么它这么慢。目前我找到的解决方案是通过自己解析域名强制IPV4:
var uri = new Uri("somedomain.com");
var builder = new UriBuilder(uri);
var addresses = await Dns.GetHostAddressesAsync(uri.Host);
builder.Host = addresses
.First(x => x.AddressFamily == AddressFamily.InterNetwork) //IPV4 only
.ToString();
var request = new HttpRequestMessage(HttpMethod.Get, builder.Uri);
request.Host = uri.Host;
也许有更好的方法。我无法使用 SocketsHttpHandler
,因为我坚持使用 .NET Framework 4.5