"An operation on a socket could not be performed" 与 HttpClientFactory



我在 Azure 上有一个长时间运行的触发 Web 作业,它使用多个类型的 http 客户端来访问远程服务。每次启动的请求量高达数百万,但在 ~30k 之后,我得到以下异常:

System.Net.Http.HttpRequestException:无法对套接字执行操作,因为系统缺少足够的缓冲区空间或队列已满。

我正在使用 Microsoft.Extensions.Http 2.2.0 将类型化的 http 客户端与 Http 客户端工厂一起注入

。到目前为止,我已经尝试使用假数据和接收器在本地运行它;并监控连接

Netstat -b

。和

var ipProperties = IPGlobalProperties.GetIPGlobalProperties((;

var tcpConnections = ipProperties.GetActiveTcpConnections((;

。但我无法重现错误;并且连接的数量始终保持不变。这让我认为连接限制以外的其他因素会导致此错误。

我会在Azure中尝试相同的方法;但这似乎不起作用,因为Kudu不允许netstat或类似的命令。

客户端将添加到如下所示的服务中:

collection.AddHttpClient<ISenderClient, SenderClient>()
.ConfigureHttpClient((provider, client) =>
{
//... configuring base url and headers
})
.SetHandlerLifetime(TimeSpan.FromMinutes(1));

然后注入到SenderClient中:

public sealed class SenderClient : ISenderClient, IDisposable
{
private readonly HttpClient _httpClient;
public SenderClient(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
public void Dispose()
{
_httpClient?.Dispose();
}
}

发件人客户端本身是从服务提供商处检索的:

_client = _provider.GetService<ISenderClient>();

。后来在 Parallel.ForEach 循环中用于分发 http 请求:

Parallel.ForEach(batches, new ParallelOptions { MaxDegreeOfParallelism = 8 }, (batch, state, i) =>
{
using (var scope = _provider.CreateScope())
{
var provider = scope.ServiceProvider;
//... dto mapping
var response = _client.SendAsync<Request, Response>(request).GetAwaiter().GetResult();
}
}

其中发送异步是

public async Task<TResponse> SendAsync<TRequest, TResponse>(TRequest request)
{
var json = JsonConvert.SerializeObject(request);
using (var content = new StringContent(json, Encoding.UTF8, "application/json"))
using (var response = await _client.PostAsync(_url, content))
{
var responseString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResponse>(responseString);
}
}

任何人都可以解释一下可能导致此异常的原因,因为到目前为止,我很难长时间尝试解决此问题..?

编辑:我相信我的问题不是这篇文章的重复,因为我使用的是HttpClientFactory而不是手动处理客户端。这应该负责管理、刷新和处置连接;并且被认为是处理 HTTP 客户端的首选方法。

使用这种方法,我应该在某个时间段内只有一个类型的连接。

我们将作业转移到具有高级定价层的应用服务,它解决了这个问题; 尽管我对这个解决方案并不完全满意。

相关内容

最新更新