【问题标题】:How to configure asp.net kestrel for low latency?如何配置 asp.net kestrel 以实现低延迟?
【发布时间】:2019-01-09 04:38:52
【问题描述】:

我正在尝试实现一个 asp.net 2.2 应用程序,以尽可能低的 延迟 服务 HTTP 请求(不是吞吐量,它不是用于生产,而是某种竞争)。该应用程序应该在具有 4 个内核的 Linux docker 容器环境中运行,并且我的处理程序受 CPU 限制,每个处理程序为 0.2..3 毫秒。连接是预先创建并保持活动状态的,但我目前正在为空处理程序(回复 200 OK)获得大约 0.6..0.8 毫秒的处理时间,有明显的抖动和偶尔的峰值到 20-50 毫秒,我不能解释一下。

Kestrel/Sockets/Threads/CLR 是否有任何特定设置可以帮助最小化每个请求的响应时间?或者如果我想将它降低到 0.1..0.2 毫秒,那么使用 EPOLL 走 C/C++ 路线是我唯一的选择?

【问题讨论】:

  • 您在 .net 上 - CLR “设计缓慢”。 “偶尔达到 20-50 毫秒” 可能是 GC 周期。如果您需要极速运行的代码 - 使用 C++ 和 boost
  • 我特别确保 GC 在这里没有发挥作用:缓冲区是预先分配和池化的,并且在处理请求时没有创建新对象。奇怪的是,即使没有 Kestrel,我在普通插座上也观察到了类似的尖峰。
  • 您无法从您的应用程序中完全控制 GC(因为 GC 不是您的应用程序的一部分),因此它的循环仍然会影响您的应用程序。
  • 怎么不是编程题?也许“设置”这个词令人困惑,改为“实施”。
  • 你必须使用 Kestrel 和 Web.API 吗?请求处理管道中有很多(有用的)中间件。如果您使用 TcpListener 实现一个简单的 HTTP 侦听器,您可能会做得更好(当然您永远不会在生产环境中这样做)。

标签: c# linux .net-core low-latency kestrel


【解决方案1】:

使用 ASP.NET Core / Kestrel 当然可以实现低延迟。

这是一个小型网络应用程序来演示这一点......

using System.Net;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

public static void Main(string[] args)
{
    IWebHost host = new WebHostBuilder()
        .UseKestrel()
        .Configure(app =>
        {
            // notice how we don't have app.UseMvc()?
            app.Map("/hello", SayHello);  // <-- ex: "http://localhost/hello"
        })
        .Build();

    host.Run();
}

private static void SayHello(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        // implement your own response
        await context.Response.WriteAsync("Hello World!");
    });
}

我在herehere之前已经多次回答过这种类似的问题。

如果您希望将 ASP.NET Core 框架与其他框架进行比较,这是一个很棒的可视化 https://www.techempower.com/benchmarks/#section=data-r16&hw=ph&test=plaintext。如您所见,ASP.NET Core 成绩斐然,是领先的 C# 框架。

在上面的代码块中,我注意到缺少app.UseMvc()。如果你确实需要它,我已经在这个答案中做了一个关于获得更好延迟的非常详细的答案:What is the difference between AddMvc() and AddMvcCore()?


.NET Core 运行时 (CoreRT)

如果您仍然需要更高的性能,我建议您查看.Net Core Runtime (CoreRT)

请注意,在撰写本文时,可能需要更详细地审查此选项,然后再将其用于生产系统。

“CoreRT 带来了本机编译的大部分性能和所有部署优势,同时保留了您使用自己喜欢的 .NET 编程语言进行编写的能力。”

CoreRT 提供了对许多应用至关重要的巨大优势。

  • 本机编译器生成一个单一文件,包括应用程序、托管依赖项和 CoreRT。
  • 本机编译的应用程序启动速度更快,因为它们执行已编译的代码。他们不需要在运行时生成机器代码,也不需要加载 JIT 编译器。
  • 本机编译的应用程序可以使用优化编译器,从而提高更高质量代码的吞吐量(C++ 编译器优化)。 LLILLC 和 IL 到 CPP 编译器都依赖于优化编译器。

这些优势为 .NET 开发人员开辟了一些新场景

  • 从一台机器上复制一个可执行文件并在另一台(同类)上运行,而无需安装 .NET 运行时。
  • 创建并运行包含单个可执行文件的 docker 映像(例如,除了 Ubuntu 14.04 之外的一个文件)。

Linux 特定优化

有一个很好的库可以尝试处理非常特殊的情况。特别是对于 Linux(但此代码对于其他操作系统是安全的)。此优化背后的原理是将libuv 传输库(ASP.NET Core 使用)替换为另一种特定于 Linux 的优化。

它直接使用内核原语来实现传输 API。这减少了堆分配对象的数量(例如uv_buf_tSocketAsyncEventArgs),这意味着 GC 压力更小。在 xplat API 之上构建的实现将汇集对象来实现这一点。

using RedHat.AspNetCore.Server.Kestrel.Transport.Linux; // <--- note this !

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseLinuxTransport()     // <--- and note this !!!
        .UseStartup()
        .Build();

// note: It's safe to call UseLinuxTransport on non-Linux platforms, it will no-op

您可以在 GitHub 上查看该中间件的存储库 https://github.com/redhat-developer/kestrel-linux-transport

来源:https://developers.redhat.com/blog/2018/07/24/improv-net-core-kestrel-performance-linux/

【讨论】:

  • 谢谢,这是我开始的。然后我什至删除了 app.Map() 并替换为 app.Run() 以消除路径解析代码,但延迟仍然比 C++/epoll() 高几倍。现在失去希望 - 除非有一些我不知道的 Socket 级别调整,否则我将不得不求助于切换任务的语言。
  • 您尝试过 CoreRT 吗?它将编译整个解决方案,您将获得更好的性能。
  • 也试过了:创建了一个原生的 Linux-x64 应用程序,但并没有显着改变结果。问题是,所有“热”代码区域都经过一定次数的迭代后进行了 JIT 优化。事实上,在某些情况下,运行时 JIT 甚至可能比静态 AOT 编译器做得更好,因为它可以在优化之前收集真实的执行统计信息,而不是进行静态分析和猜测,因此在启动后运行良好的“热身”会触发 JIT 优化。
  • 对于您声称更快的本机 C/C++ 对应项,您使用的是 libuv / kestrel 吗?性能问题可能不在于语言,而在于请求处理的核心技术。
  • 我为linux优化添加了额外的内容
【解决方案2】:

感谢所有回答的人。我最终用 epoll_wait() 系统调用实现了我自己的 HTTP 服务器,这是将延迟降低到我需要的水平的唯一方法。 Kestrel 提供大约 2-2.5 倍的延迟。

请记住,Kestrel 仍然是大多数生产需求的绝佳选择,它已针对具有合理延迟的最大吞吐量进行了优化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-28
    • 1970-01-01
    • 2021-01-06
    • 1970-01-01
    • 2017-03-23
    • 2019-09-29
    • 2017-09-01
    • 2021-08-28
    相关资源
    最近更新 更多