Cet article explore notre décision de nous éloigner de l'architecture réactive dans notre projet logiciel. Nous approfondirons les principes fondamentaux des systèmes réactifs, les avantages des E/S non bloquantes et les défis auxquels nous sommes confrontés avec une approche réactive.
Reactive englobe un ensemble de principes et de lignes directrices visant à construire des systèmes et des applications distribués réactifs, caractérisés par :
L'un des principaux avantages des systèmes réactifs est leur utilisation d'E/S non bloquantes. Cette approche évite de bloquer les threads lors des opérations d'E/S, permettant à un seul thread de gérer plusieurs requêtes simultanément. Cela peut améliorer considérablement l'efficacité du système par rapport au blocage traditionnel des E/S.
Dans le multithreading traditionnel, les opérations de blocage posent des défis importants dans l'optimisation des systèmes (Figure 1). Les applications gourmandes consommant trop de mémoire sont inefficaces et pénalisent les autres applications, nécessitant souvent des demandes de ressources supplémentaires comme de la mémoire, du processeur ou des machines virtuelles plus volumineuses.
Figure 1 – Multi-threading traditionnel
Les opérations d'E/S font partie intégrante des systèmes modernes, et leur gestion efficace est primordiale pour éviter les comportements gourmands. Les systèmes réactifs utilisent des E/S non bloquantes, permettant à un faible nombre de threads du système d'exploitation de gérer de nombreuses opérations d'E/S simultanées.
Bien que les E/S non bloquantes offrent des avantages substantiels, elles introduisent un nouveau modèle d'exécution distinct des frameworks traditionnels. Une programmation réactive a émergé pour résoudre ce problème, car elle atténue l'inefficacité des threads de plate-forme inactifs pendant les opérations de blocage (Figure 2).
Figure 2 – Boucle d'événement réactif
Quarkus exploite un moteur réactif alimenté par Eclipse Vert.x et Netty, facilitant les interactions E/S non bloquantes. Mutiny, l'approche privilégiée pour écrire du code réactif avec Quarkus, adopte un paradigme événementiel, dans lequel les réactions sont déclenchées par les événements reçus.
Mutiny propose deux types événementiels et paresseux :
Bien que les systèmes réactifs offrent des avantages, nous avons rencontré plusieurs défis lors du développement :
"En effet, le rapport entre le temps passé à lire et à écrire est bien supérieur à 10 pour 1. Nous lisons constamment du vieux code dans le cadre de l'effort d'écrire du nouveau code. ...[Par conséquent,] le rendre facile à lire rend la lecture plus facile. c'est plus facile d'écrire."
―Robert C. Martin, Clean Code : Un manuel d'artisanat logiciel agile
Voici un exemple de code réactif utilisant Mutiny pour illustrer la complexité :
Multi.createFrom().ticks().every(Duration.ofSeconds(15)) .onItem().invoke(() - > Multi.createFrom().iterable(configs()) .onItem().transform(configuration - > { try { return Tuple2.of(openAPIConfiguration, RestClientBuilder.newBuilder() .baseUrl(new URL(configuration.url())) .build(MyReactiveRestClient.class) .getAPIResponse()); } catch (MalformedURLException e) { log.error("Unable to create url"); } return null; }).collect().asList().toMulti().onItem().transformToMultiAndConcatenate(tuples - > { AtomicInteger callbackCount = new AtomicInteger(); return Multi.createFrom().emitter(emitter - > Multi.createFrom().iterable(tuples) .subscribe().with(tuple - > tuple.getItem2().subscribe().with(response - > { emitter.emit(callbackCount.incrementAndGet()); if (callbackCount.get() == tuples.size()) { emitter.complete(); } }) )); }).subscribe().with(s - > {}, Throwable::printStackTrace, () - > doSomethingUponComplete())) .subscribe().with(aLong - > log.info("Tic Tac with iteration: " + aLong));
Project Loom, a recent development in the Java ecosystem, promises to mitigate the issues associated with blocking operations. By enabling the creation of thousands of virtual threads without hardware changes, Project Loom could potentially eliminate the need for a reactive approach in many cases.
"Project Loom is going to kill Reactive Programming"
―Brian Goetz
In conclusion, our decision to move away from reactive architecture style a pragmatic approach to our project's long-term maintainability. While reactive systems offer potential benefits, the challenges they presented for our team outweighed those advantages in our specific context.
Importantly, this shift did not compromise performance. This is a positive outcome, as it demonstrates that a well-designed non reactive(imperative) architecture can deliver the necessary performance without the complexity associated with reactive architecture in our case.
As we look towards the future, the focus remains on building a codebase that is not only functional but also easy to understand and maintain for developers of all experience levels. This not only reduces development time but also fosters better collaboration and knowledge sharing within the team.
In the graph below, theX-axisrepresents the increasing complexity of our codebase as it evolves, while theY-axisdepicts the time required for these developmental changes.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!