servidor net dotnet asp asp.net-core kestrel-http-server

asp.net core - net - ¿Kestrel está utilizando un solo hilo para procesar solicitudes como Node.js?



kestrel web server (2)

El enhebrado es específico del transporte. Con el transporte libuv (el valor predeterminado en 2.0) como se indica en la respuesta de Daniel JG , hay una serie de bucles de eventos basados ​​en la cantidad de procesadores lógicos en la máquina y eso se puede anular configurando el valor en las opciones. Por defecto, cada conexión está vinculada a un hilo particular y todas las operaciones de E / S tienen lugar en ese hilo. El código de usuario se ejecuta en subprocesos del grupo de subprocesos porque no confiamos en que los usuarios no bloqueen los subprocesos de E / S. Cuando realiza llamadas de E / S en estos subprocesos de grupo de subprocesos (es decir, HttpResponse.WriteAsync ), kestrel hace el trabajo de ordenar que regrese al subproceso de E / S apropiado al que estaba vinculado el socket. Un flujo de solicitud típico se ve así:

[lectura de la red] despacho al grupo de subprocesos -> [análisis http], [ejecutar canalización de middleware] llamada para escribir -> poner en cola el trabajo del usuario en el subproceso IO [escribir en la red]

Por supuesto, siempre puede decirle a Kestrel que es un profesional y que nunca bloqueará el hilo IO y ejecutará su código en él. Pero no lo haría a menos que supiera lo que estaba haciendo (y no: D).

Tanto Kestrel como Node.js están basados ​​en libuv .

Si bien Node.js afirma exactamente que usa un bucle de eventos , parece que no puedo encontrar si ese es el caso de Kestrel, o si utiliza la agrupación de hilos / cola de solicitud como IIS.

Cernícalo detrás de un servidor web

Node.js evento loop

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


Actualizado para ASP.Net Core 2.0 . Como señaló poke, el servidor se ha dividido entre alojamiento y transporte, donde libuv pertenece a la capa de transporte. El libuv ThreadCount se ha movido a sus propias LibuvTransportOptions y se configuran por separado en su generador de host web con el UseLibuv() ext:

  • Si LibuvTransportOptions clase LibuvTransportOptions en github, verá una opción 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;

  • La opción se puede configurar en la llamada a UseLibuv , en su generador de alojamiento web. Por ejemplo:

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

Mientras que en ASP.NET Core 1.X, la configuración de Libuv era parte del servidor kestrel:

  • Si KestrelServerOptions clase KestrelServerOptions en su repositorio github, verá que hay una opción 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;

  • La opción se puede configurar en la llamada a UseKestrel , por ejemplo, en una nueva aplicación 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(); }

Excavando a través del código fuente:

Entonces podríamos decir que usa múltiples bucles de eventos libuv para IO. El trabajo real se realiza en código administrado con subprocesos de trabajo estándar, utilizando el grupo de subprocesos CLR.

Me encantaría encontrar más documentación autorizada sobre esto ( Kestrel no dan muchos detalles). El mejor que he encontrado es Damian Edwards hablando de Kestrel en el canal 9 . Alrededor del minuto 12, explica:

  • libuv usa un modelo de bucle de eventos de un solo hilo
  • Kestrel admite múltiples bucles de eventos.
  • Kestrel solo hace trabajo de IO en los bucles de eventos de libuv
  • Todo el trabajo que no sea de E / S (incluido todo lo relacionado con HTTP, como análisis, encuadre, etc.) se realiza en código administrado en subprocesos de trabajo .net estándar.

Además, una búsqueda rápida ha devuelto:

  • David Fowler hablando sobre la agrupación de hilos en Kestrel here . También confirma que una solicitud aún podría saltar entre hilos en ASP.Net Core. (como era en versiones anteriores)
  • Esta blogpost mirando a Kestrel cuando salió
  • Esta question sobre cómo se administran los hilos en ASP.Net Core.