web-dev-qa-db-fra.com

Kestrel utilise-t-il un seul thread pour traiter les requêtes comme Node.js?

Kestrel et Node.js sont tous deux basés sur libuv .

Bien que Node.js indique exactement qu'il utilise ne boucle d'événement , je n'arrive pas à déterminer si tel est le cas pour Kestrel ou s'il utilise une file d'attente de pooling/de requêtes de threads comme IIS?

Kestrel derrière un serveur web

Kestrel behind a web server

Boucle d'événement Node.js

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

Mise à jour pour ASP.Net Core 2.0. Comme indiqué par poke, le serveur a été divisé entre hébergement et transport, libuv appartenant à la couche de transport. Libuv ThreadCount a été déplacé vers son propre LibuvTransportOptions et ils sont définis séparément dans votre générateur d’hébergeur Web avec la méthode UseLibuv() ext:

  • Si vous cochez la classe LibuvTransportOptions dans github, vous verrez une option 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;
    
  • L'option peut être définie dans l'appel à UseLibuv, dans votre générateur hôte Web. Par exemple:

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

Dans ASP.NET Core 1.X, la configuration de Libuv faisait partie du serveur Kestrel:

  • Si vous cochez la classe KestrelServerOptions dans son dépôt github, vous verrez qu'il existe une option 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;
    
  • L'option peut être définie dans l'appel à UseKestrel, par exemple dans une nouvelle application 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();
    }
    

Creuser dans le code source:

  • Vous pouvez voir les threads d'écoute de libuv (ou KestrelThreads ) étant créés dans le KestrelEngine
  • Certains emplacements appellent les méthodes ThreadPool pour pouvoir exécuter du code dans le pool de threads CLR au lieu des threads libuv. (En utilisant ThreadPool.QueueUserWorkItem). Le pool semble être configuré par défaut avec un maximum de 32K threads qui peut être modifié via config .
  • Le Frame<TContext> délégués à l'application réelle (comme une application ASP.Net Core) pour traiter la demande.

On pourrait donc dire qu'il utilise plusieurs eventLops libuv pour IO. Le travail réel est effectué sur du code géré avec des threads de travail standard, à l'aide du pool de threads CLR.

J'aimerais trouver plus de documentation faisant autorité à ce sujet (les documents officiels ne donnent pas beaucoup de détails). Le meilleur que j'ai trouvé est Damian Edwards qui parle de Kestrel on channel 9 . Vers la minute 12, il explique:

  • libuv utilise un modèle de boucle d'événement à un seul thread
  • Kestrel prend en charge plusieurs boucles d'événement
  • Kestrel ne fait que IO travailler sur les boucles d’événements libuv
  • Tout le travail non IO (y compris tout ce qui concerne HTTP, comme l'analyse syntaxique, le cadrage, etc.) est effectué en code managé sur des threads de travail .net standard.

De plus, une recherche rapide est revenue:

  • David Fowler parle de pool de threads dans Kestrel ici . Cela confirme également qu'une requête peut toujours passer d'un thread à l'autre dans ASP.Net Core. (comme dans les versions précédentes)
  • This blogpost regardant Kestrel quand il est sorti
  • Cette question sur la façon dont les threads sont gérés dans ASP.Net Core.
75
Daniel J.G.

Le filetage est spécifique au transport. Avec le transport libuv (la valeur par défaut en 2.0) comme indiqué dans la réponse de Daniel JG , il existe un certain nombre de boucles d'événement basées sur le nombre de processeurs logiques sur la machine et qui peuvent être annulées en définissant la valeur sur le paramètre. options. Par défaut, chaque connexion est liée à un thread particulier et toutes les opérations IO ont lieu sur ce thread. Le code utilisateur est exécuté sur les threads du pool de threads car nous ne pensons pas que les utilisateurs ne bloqueront pas = IO threads. Lorsque vous effectuez IO appelle sur ces threads du pool de threads (c.-à-d. HttpResponse.WriteAsync), Kestrel fait le travail pour le rediriger vers le thread IO) auquel le socket était lié. Un flux de requête typique ressemble à ceci:

[lire à partir du réseau] dispatch dans le pool de threads -> [analyse syntaxique http], [exécuter le pipeline de middleware] pour écrire -> mettre en file d'attente le travail de l'utilisateur sur le IO thread [écriture sur le réseau]

Bien sûr, vous pouvez toujours dire à Kestrel que vous êtes un professionnel et que vous ne bloquerez jamais le fil IO) et que vous exécutez votre code. Mais je ne le ferais pas à moins de savoir ce que je faisais (et je ne t: D).

39
davidfowl