1. ホーム
  2. asp.net-core

KestrelはNode.jsのようにリクエストの処理にシングルスレッドを使っているのでしょうか?

2023-11-27 14:13:49

質問

どちらも ケストレル Node.js libuv .

Node.jsでは、正確に イベントループ を使用すると書いてありますが、Kestrelがそうなのか、それともIISのようにスレッドプーリング/リクエストキューを利用するのか、見つけることができないようです。

Web サーバーの背後にある Kestrel

Node.jsのイベントループ

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

どのように解決するのですか?

ASP.Net Core 2.0用に更新しました。 . poke さんのご指摘の通り、サーバはホスティングとトランスポートに分かれており、libuv はトランスポート層に属しています。libuv の ThreadCount はそれ自身の LibuvTransportOptions で、これらはウェブホストビルダーで別々に設定されます。 UseLibuv() ext メソッドで設定します。

  • を確認すると LibuvTransportOptions クラスをgithubで確認すると ThreadCount というオプションがあります。

    /// <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 configはkestrelサーバーの一部でした。

  • を確認すると KestrelServerOptions クラスを確認すると、その github リポにある ThreadCount オプションがあります。

    /// <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 を呼び出す際に設定できます。

    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 ) が作成されていることがわかります。 KestrelEngine
  • 場所によっては ThreadPool メソッドを呼び出し、libuv スレッドの代わりに CLR スレッドプールでコードを実行できるようにします。(使用する ThreadPool.QueueUserWorkItem ). プールはデフォルトで 最大 32K スレッド となっているようですが、これは変更可能で 設定により .
  • Frame<TContext> は、リクエストを処理するために実際のアプリケーション (ASP.Net Core アプリケーションなど) に委譲します。

つまり、IOのために複数のlibuvイベントループを使用していると言えます。実際の作業は、CLR スレッドプールを使用した標準的なワーカスレッドによるマネージドコードで行われます。

これに関するもっと権威あるドキュメントを見つけたいのですが ( 公式ドキュメント はあまり詳細を与えてくれません)。私が見つけた中で最も良いものは、Damian Edwards が チャンネル 9 . 12分ごろに彼が説明しています。

  • libuv はシングルスレッドイベントループモデルを使用します。
  • Kestrel は複数のイベントループをサポートする
  • Kestrel は libuv イベントループの IO 作業のみを行います。
  • すべての非 IO 作業 (解析、フレーミングなどの HTTP に関連するものを含む) は、標準の .net ワーカスレッド上のマネージドコードで行われます。

さらに、クイック検索で戻ってきました。

  • David Fowler が Kestrel でのスレッドプーリングについて話しています。 ここで . また、ASP.Net Core ではリクエストがスレッド間を飛び交う可能性があることも確認できました。(以前のバージョンでそうであったように)
  • これは ブログ記事 Kestrel が登場したときの様子
  • この 質問 は、ASP.Net Coreでスレッドがどのように管理されているかについての質問です。