Kestrel 是否像 Node.js 一样使用单线程来处理请求?

2024-01-11

Both Kestrel https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel and Node.js https://nodejs.org/en/about是基于libuv https://github.com/libuv/libuv.

虽然 Node.js 明确指出它使用事件循环 https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/,我似乎无法找到 Kestrel 是否属于这种情况,或者它是否像 IIS 一样利用线程池/请求队列?

Kestrel 位于 Web 服务器后面

Node.js 事件循环

    ┌───────────────────────┐
 ┌─>│        timers         │
 │  └──────────┬────────────┘
 │  ┌──────────┴────────────┐
 │  │     I/O callbacks     │
 │  └──────────┬────────────┘
 │  ┌──────────┴────────────┐
 │  │     idle, prepare     │
 │  └──────────┬────────────┘      ┌───────────────┐
 │  ┌──────────┴────────────┐      │   incoming:   │
 │  │         poll          │<─────┤  connections, │
 │  └──────────┬────────────┘      │   data, etc.  │
 │  ┌──────────┴────────────┐      └───────────────┘
 │  │        check          │
 │  └──────────┬────────────┘
 │  ┌──────────┴────────────┐
 └──┤    close callbacks    │
    └───────────────────────┘

更新为 ASP.Net Core 2.0。正如 poke 所指出的,服务器已分为托管层和传输层,其中 libuv 属于传输层。利布夫ThreadCount已移至其自己的LibuvTransportOptions它们在您的网络主机构建器中单独设置UseLibuv()扩展方法:

  • 如果您检查LibuvTransportOptions https://github.com/aspnet/KestrelHttpServer/blob/rel/2.0.0/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/LibuvTransportOptions.csgithub中的类,你会看到一个ThreadCount option:

    /// <summary>
    /// The number of libuv I/O threads used to process requests.
    /// </summary>
    /// <remarks>
    /// Defaults to half of <see cref="Environment.ProcessorCount" /> rounded down and clamped between 1 and 16.
    /// </remarks>
    public int ThreadCount { get; set; } = ProcessorThreadCount;
    
  • 该选项可以在调用中设置UseLibuv,在您的网络主机构建器中。例如:

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseLibuv(opts => opts.ThreadCount = 4)
            .UseStartup<Startup>()                
            .Build();
    

在 ASP.NET Core 1.X 中,Libuv 配置是 kestrel 服务器的一部分:

  • 如果您检查KestrelServerOptions https://github.com/aspnet/KestrelHttpServer/blob/rel/1.1.0/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerOptions.cs在其 github 存储库中的类中,您会看到有一个ThreadCount option:

    /// <summary>
    /// The number of libuv I/O threads used to process requests.
    /// </summary>
    /// <remarks>
    /// Defaults to half of <see cref="Environment.ProcessorCount" /> rounded down and clamped between 1 and 16.
    /// </remarks>
    public int ThreadCount { get; set; } = ProcessorThreadCount;
    
  • 该选项可以在调用中设置UseKestrel,例如在新的 ASP.Net Core 应用程序中:

    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel(opts => opts.ThreadCount = 4)
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();
    
        host.Run();
    }
    

深入挖掘源代码:

  • 您可以看到 libuv 侦听器线程(或KestrelThreads https://github.com/aspnet/KestrelHttpServer/blob/rel/1.1.0/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/KestrelThread.cs)被创建于KestrelEngine https://github.com/aspnet/KestrelHttpServer/blob/rel/1.1.0/src/Microsoft.AspNetCore.Server.Kestrel/Internal/KestrelEngine.cs
  • 有的地方会调用ThreadPool https://github.com/aspnet/KestrelHttpServer/blob/rel/1.1.0/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/LoggingThreadPool.cs方法,以便它们可以在 CLR 线程池而不是 libuv 线程中运行代码。 (使用ThreadPool.QueueUserWorkItem)。该池似乎默认有一个最多 32K 线程 https://github.com/dotnet/corefx/issues/15990#issuecomment-279023245可以修改通过配置 https://github.com/dotnet/cli/issues/889.
  • The Frame<TContext> https://github.com/aspnet/KestrelHttpServer/blob/rel/1.1.0/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/FrameOfT.cs委托给实际应用程序(例如 ASP.Net Core 应用程序)来处理请求。

所以我们可以说它使用多个 libuv eventloops 进行 IO。实际工作是使用 CLR 线程池通过标准工作线程在托管代码上完成的。

我很想找到关于此的更多权威文档(官方文档 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel不提供太多细节)。我发现的最好的一篇是达米安·爱德华兹 (Damian Edwards) 在频道 9 https://channel9.msdn.com/Events/ASPNET-Events/ASPNET-Fall-Sessions/ASPNET-5-Kestrel。第 12 分钟左右,他解释道:

  • libuv 使用单线程事件循环模型
  • Kestrel 支持多个事件循环
  • Kestrel 在 libuv 事件循环上仅进行 IO 工作
  • 所有非 IO 工作(包括与 HTTP 相关的任何工作,如解析、成帧等)都是在标准 .net 工作线程上的托管代码中完成的。

此外,还返回了快速搜索:

  • David Fowler 谈论 Kestrel 中的线程池here https://github.com/aspnet/Home/issues/1371。它还确认请求仍可能在 ASP.Net Core 中的线程之间跳转。 (就像以前的版本一样)
  • This blogpost http://blog.dotnetnerd.dk/post/2015/11/08/Kestrel-the-new-web-server-for-ASPNET-5.aspx当 Kestrel 出来时,看着它
  • This question https://forums.asp.net/t/2096701.aspx?Where+is+the+settings+for+managing+threads+and+their+options关于如何在 ASP.Net Core 中管理线程。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kestrel 是否像 Node.js 一样使用单线程来处理请求? 的相关文章

随机推荐