- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个非常简单的 API,它有一个单例实例,其中有许多在整个应用程序中重复使用的 HTTPClient。调用API时,我创建一个任务列表,每个任务调用一个客户端。我使用 CancellationToken 和另一个任务来实现严格的超时。
public class APIController : Controller
{
private IHttpClientsFactory _client;
public APIController(IHttpClientsFactory client)
{
_client = client;
}
[HttpPost]
public async Task<IActionResult> PostAsync()
{
var cts = new CancellationTokenSource();
var allTasks = new ConcurrentBag<Task<Response>>();
foreach (var name in list)//30 clients in list here
{
allTasks.Add(CallAsync(_client.Client[name], cts.Token));
}
cts.CancelAfter(1000);
await Task.WhenAny(Task.WhenAll(allTasks), Task.Delay(1000));
//do something with allTasks
}
}
CallAsync也很简单,只需使用客户端调用并等待应答即可。
var response = await client.PostAsync(endpoint, content, token);
现在这段代码工作正常,1秒后返回,然后将取消请求发送到任何尚未返回的任务。任务列表大约有 30 个客户端,因此每次调用 API 都会调用 30 个端点,平均响应时间为 800ms。
该应用程序每秒管理 3000 个并发调用,因此每秒执行大约 100k Httpclient 调用。
问题是 HttpClient 存在一些瓶颈,事实上 CPU 总是非常高,我需要大约 80 个(八个)16 核虚拟机和 32GB RAM 来处理流量。显然有什么问题。
我得到的一个提示是,在将我的 block 包更新到 Asp.net Core 2 之前,完全相同的代码执行得更好。
我对服务器进行了诊断,我的代码中没有任何错误,但看起来 HttpClients 客户端有点互相等待或卡住了。
跟踪中确实没有其他内容。我正在使用工厂为每个端点创建单个实例:
public class HttpClientsFactory : IHttpClientsFactory
{
public static Dictionary<string, HttpClient> HttpClients { get; set; }
public HttpClientsFactory()
{
HttpClients = new Dictionary<string, HttpClient>();
Initialize();
}
private static void Initialize()
{
HttpClients.Add("Name1", CreateClient("http://......"));
HttpClients.Add("Name2", CreateClient("http://...."));
HttpClients.Add("Name3", CreateClient("http://...."));
}
public Dictionary<string, HttpClient> Clients()
{
return HttpClients;
}
public HttpClient Client(string key)
{
try
{
return Clients()[key];
}
catch
{
return null;
}
}
public static HttpClient CreateClient(string endpoint)
{
try
{
var config = new HttpClientHandler()
{
MaxConnectionsPerServer = int.MaxValue,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var client = new HttpClient(config)
{
Timeout = TimeSpan.FromMilliseconds(1000),
BaseAddress = new Uri(endpoint)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Connection.Clear();
client.DefaultRequestHeaders.ExpectContinue = false;
client.DefaultRequestHeaders.ConnectionClose = false;
client.DefaultRequestHeaders.Connection.Add("Keep-Alive");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
catch (Exception)
{
return null;
}
}
}
然后在启动中
services.AddSingleton<IHttpClientsFactory, HttpClientsFactory>();
这里发生了什么,HttpClient 的单例不适合这种情况吗?我应该为每个线程创建一个 HttpClient 实例吗?我该怎么做?
更新
经过几天的测试,我确信 HTTPClient 调用期间的超时会导致一些连接打开,从而导致端口耗尽。关于如何避免这种情况有什么建议吗?
最佳答案
由于 HTTP 的设计工作方式,听起来您已经达到了操作系统处理 HTTP 请求的极限。如果您使用 .NET 框架(而不是 dotnet core),那么您可以使用 ServicePointManager
调整操作系统管理 HTTP 请求的方式。 。大多数 HTTP 服务器和客户端都使用 keep-alive,这意味着它们将为多个 HTTP 请求重用同一个 TCP 连接。您可以使用 ServicePointManager.FindServicePoint()
函数获取 ServicePoint
用于连接到特定主机的实例。对同一主机的每个 HTTP 请求都使用相同的 ServicePoint
实例。
尝试调整 ServicePoint
中的一些值,看看它如何影响您的应用程序。例如ConnectionLimit
,它控制客户端和服务器之间将使用多少个并行 TCP 连接。而 keep-alive
可以让您为新的 HTTP 请求重用现有的 TCP 连接,以及 pipelined
(使用 SupportsPipelining
检查您要连接的服务器是否支持此功能)允许您同时发送多个请求,HTTP 要求响应的顺序与请求的顺序相同。这意味着最初的缓慢响应将阻止所有后续请求/响应。通过拥有多个 TCP 连接,您可以并行地拥有多个非阻塞 HTTP 请求。但当然也有一个缺点,因为您现在有多个 TCP 连接,它们必须相互争夺网络资源。因此,调整这个值并看看它是否有所改善,但要小心!
如上所述,这里真正的问题可能是 HTTP 协议(protocol)以及它如何一次只能处理一个请求。幸运的是,HTTP/2 中有一个解决方案,不幸的是,asp.net 还没有很好地支持这一点。我还没有尝试过,因为我工作的系统还不支持它,但理论上它应该允许您并行发送和接收多个 HTTP 请求而不会阻塞。看看this thread它描述了一种让它工作的方法。
编辑
我完全错过了你正在 asp.net core 2.0 上运行。在这种情况下你 don't have access to ServicePointManager
。但如果您只需要在 Windows 上运行,那么您可以安装 WinHttpHandler
nuget 并设置 MaxConnectionsPerServer
属性(property)。但如果您使用的是 WinHttpHandler
,那么我建议您尝试 HTTP/2,看看这是否会为您带来改善。
编辑2
我们刚刚发现一个问题,即 POST 请求花费的时间是 GET 请求的两倍,尽管请求的其余部分完全相同。当将 localhost 连接到本地服务器时,我们从异地位置发现了该问题,因此 ping 值比正常情况下高得多。这表明在执行 POST 时进行了两次往返,而在执行 GET 时仅进行了一次往返。解决方案是这两行:
ServicePointManager.UseNagleAlgorithm = false;
ServicePointManager.Expect100Continue = false;
也许这对你也有帮助?
关于asp.net-core - C# Httpclient Asp.net Core 2.0 on Kestrel 等待、锁定争用、CPU 高,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46086293/
我曾尝试在 net.core 文档(问题等)上搜索信息但没有结果。 代码更简单: [HttpGet()] [Route("dob")] public string dobTes
对于部署在单个 AWS EC2 主机上的 .NET Core 2.2 应用程序,我比较了 IIS 托管与普通 Kestrel 托管。 对于 IIS 配置,我遵循 MS documentation .
我使用.net core 2.1并将其发布到IIS 8.5。我很难理解 .NET 核心托管的概念。 program.cs 是 public class Program { public sta
我有一个新的 ASP.NET 5 项目并按如下方式设置 project.json; "frameworks": { "dnx451": { "dependencies
我正在努力完成以下任务:我有一个运行 gRPC 服务的 asp.net core 3.1。 在应用程序的生命周期中,我希望能够暂停/停止端点/服务器监听/接受请求,并在一段时间后恢复它。 只是为了澄清
我已使用示例默认值在 Visual Studio 2019 中创建了无状态服务(创建新项目 -> Service Fabric 应用程序 -> 命名项目和解决方案 -> 无状态 ASP.NET Cor
我已使用示例默认值在 Visual Studio 2019 中创建了无状态服务(创建新项目 -> Service Fabric 应用程序 -> 命名项目和解决方案 -> 无状态 ASP.NET Cor
我们正在尝试使用 VSCode 在 Mac 上编写 ASP.NET 应用程序。我们已经成功安装了 VSCode、DNX、Yeoman、Node.js 和 npm,以及 the ASP.NET guid
我确实遇到了红隼的一个奇怪问题。我无法上传超过红隼 MaxRequestBodySize 的多个文件。 当我试图阅读 this.Request.Form.Files.GetFiles() 时,预期的行
官方MS-documentation说如果我想在 linux 上托管一个 ASP.NET 核心应用程序,我应该在它前面放置一个 apache 或 nginx 反向代理。但是,我找不到任何我应该这样做的
通过 HTTP 和 Visual Studio 内部它工作正常。但是,当我尝试通过 HTTPS 访问端点时,我看到了这个错误,我不完全确定如何解决这个问题: info: Microsoft.AspNe
我已完成以下操作,但仍然无效。运行 dotnet myapp.dll 仍然显示它正在监听 http://localhost:5000 . 创建hosting.json 代码: { "server.
我正在尝试使用 kestrel 创建 Web 应用程序。本文中https://learn.microsoft.com/pl-pl/aspnet/core/fundamentals/servers/ke
我知道不建议将 Kestrel Web 服务器暴露给外界,但将 Kestrel 置于 IIS 之后所损失的性能并不是一件可以轻易忽略的事情。 (事实上 ,迁移到 .net core 可能会失去所有
我在带有 VS2017 (15.3.5) 的 Win 7 上使用 Asp.Net core 2.0.2。 我当前的 Kestrel 配置如下所示: return WebHost.CreateDefau
如何在 Linux/OSX 上以持久的方式运行 Kestrel 网络服务器?我能够按预期运行网络服务器: 红隼 但是,我还没有找到一种方法来让它持久化,即 k 红隼 & 进程开始然后立即停止。 最佳答
我正在学习如何在 ASP.NET Core 2 中工作,我遇到了一个相当烦人的问题。每当我运行我的应用程序时,Kestrel 服务器都会忽略我的端点配置,而是开始监听一个随机端口。不用说,这不是我所期
我们有一个 ASP.NET Core 2.x 应用程序,它实现了自定义中间件,充当另一个(基于 Java 的)服务器/应用程序前面的代理。在服务器请求完成之前,此应用程序/中间件的客户端经常中止/取消
我需要通知 systemd 我的服务已成功启动,启动后需要运行的任务要求服务器已经在监听目标 Unix域套接字。 我正在使用 IWebHost::Run 来启动服务器,这是一个阻塞调用。此外,我找不到
我有以下设置:在应用程序负载均衡器 (AWS) 后面的几个 linux 容器(基于 aspnetcore 2.0.5 构建)中运行的 web api 正在使用 HttpClient 向此 api 发出
我是一名优秀的程序员,十分优秀!