web-dev-qa-db-fra.com

Modèle de filetage de Spring WebFlux et Reactor

Expérimente actuellement la programmation réactive avec Spring 5.0.0.RC2, Reactor 3.1.0.M2 et Spring Boot 2.0.0.M2.

Vous vous interrogez sur le modèle de concurrence et de thread utilisé par WebFlux et Reactor pour coder correctement l'application et gérer l'état mutable.

Le document Reactor indique que la bibliothèque est considérée comme indépendante de la concurrence et mentionne l'abstraction du planificateur. Le document WebFlux ne donne aucune information.

Pourtant, lors de l'utilisation de WebFlux via Spring Boot, un modèle de thread est défini.

De mes expérimentations voici ce que j'ai obtenu:

  • Le modèle n'est ni 1 thread d'événement, ni 1 thread d'événement + travailleurs
  • Plusieurs pools de threads sont utilisés
  • " threads réacteur-http-nio-3 ": probablement un par cœur, gérer les requêtes HTTP entrantes
  • " Thread-7 " threads: utilisé par les requêtes asynchrones vers les ressources MongoDB ou HTTP
  • Threads " parallel-1 ": un par coeur, créé par Schedulers.parallel () à partir de Reactor, utilisé par les opérateurs de délai et autres
  • L'état mutable partagé doit être synchronisé par l'application
  • ThreadLocal (pour l'état de l'application, la journalisation MDC, etc.) ne sont pas à portée de demande, donc ne sont pas très intéressants

Est-ce correct ? Quel est le modèle de concurrence et de threading de WebFlux: par exemple, quels sont les pools de threads par défaut?

Merci pour l'information

21
Florian Beaufumé

Après la question, le la documentation actuelle fournit quelques indices sur le modèle de concurrence et les threads auxquels on peut s'attendre (mais je pense toujours que des descriptions plus claires/meilleures de ce qui se passe sous la scène à partir d'un multi- perspective de filetage serait très appréciée par les nouveaux arrivants du printemps).

Il explique la différence entre Spring MVC et Spring WebFlux (modèle à 1 thread par demande vs boucle d'événements):

Dans Spring MVC et les applications de servlet en général, il est supposé que les applications peuvent bloquer le thread actuel, par ex. pour les appels distants, et pour cette raison, les conteneurs de servlets utilisent un grand pool de threads, pour absorber le blocage potentiel lors du traitement des demandes.

Dans Spring WebFlux, et les serveurs non bloquants en général, il est supposé que les applications ne bloqueront pas, et donc les serveurs non bloquants utilisent un petit pool de threads de taille fixe (travailleurs de boucle d'événements) pour gérer les demandes. Appel d'une API de blocage

Mais notez que les applications Spring MVC peuvent également introduire une certaine asynchronicité (cf. Servlet 3 Async). Et je suggère cette présentation pour une discussion avec Servlet 3.1 NIO et WebFlux.

Retour aux documents: cela suggère également que, lorsque vous travaillez avec des flux réactifs, vous avez un certain contrôle:

Et si vous avez besoin d'utiliser une bibliothèque de blocage?

Reactor et RxJava fournissent à l'opérateur publishOn de poursuivre le traitement sur un thread différent.

(Pour plus de détails à ce sujet, reportez-vous à planification dans Reactor )

Il traite également des threads que vous pouvez attendre dans les applications WebFlux ( bold est le mien):

Modèle de filetage

Quels threads devriez-vous vous attendre à voir sur un serveur fonctionnant avec Spring WebFlux?

  • Sur un serveur WebFlux "Vanilla" Spring (par exemple, pas d'accès aux données, ni d'autres dépendances facultatives), vous pouvez vous attendre un thread pour le serveur, et plusieurs autres pour le traitement des demandes (généralement autant que le nombre de cœurs CPU) . Les conteneurs de servlets, cependant, peuvent commencer avec plus de threads (par exemple 10 sur Tomcat), à la fois pour les servlets, bloquant les E/S et les servlets 3.1, pour les E/S non bloquantes.
  • Le WebClient réactif fonctionne dans le style de boucle d'événement . Vous verrez donc un petit nombre fixe de threads de traitement liés à cela, par exemple "réacteur-http-nio-" avec le connecteur Reactor Netty . Cependant, si Reactor Netty est utilisé à la fois pour le client et le serveur, les deux partageront les ressources de boucle d'événements par défaut.
  • Reactor et RxJava fournissent des abstractions du pool de threads, appelées Schedulers , à utiliser avec l'opérateur publishOn utilisé pour changer de traitement à un pool de threads différent . Les ordonnanceurs ont des noms qui suggèrent une stratégie d'accès concurrentiel spécifique , par exemple "parallèle" pour le travail lié au processeur avec un nombre limité de threads, ou "élastique" pour les E/S travail lié avec un grand nombre de threads. Si vous voyez de tels threads, cela signifie qu'un code utilise une stratégie spécifique de planificateur de pool de threads.
  • Les bibliothèques d'accès aux données et autres dépendances tierces peuvent également créer et utiliser leurs propres threads .

En partie, vous pouvez configurer les détails du modèle de filetage via la configuration

Pour configurer le modèle de thread pour un serveur, vous devrez utiliser des API de configuration spécifiques au serveur, ou si vous utilisez Spring Boot, vérifiez les options de configuration de Spring Boot pour chaque serveur. Le WebClient peut être configuré directement. Pour toutes les autres bibliothèques, reportez-vous à leur documentation respective.

De plus, comme par exemple la discussion Nombre de threads par défaut dans la configuration webflux réactive Spring boot 2. met en évidence,

Le nombre de threads par défaut pour le traitement des demandes est déterminé par le serveur Web sous-jacent; par défaut, Spring Boot 2.0 utilise Reactor Netty, qui utilise les valeurs par défaut de Netty

il s'agit de composants par défaut et de leurs valeurs par défaut (et de la configuration globale, y compris celle injectée de manière transparente via des annotations) - qui peuvent également changer d'une version à l'autre de Spring/Boot et des dépendances correspondantes. Dit cela, vos suppositions semblent correctes.

17
metaphori