Home> Java> javaTutorial> body text

Why we discarded Reactive systems architecture from our code?

王林
Release: 2024-08-30 06:00:35
Original
771 people have browsed it

This article explores our decision to move away from reactive architecture in our software project. We'll delve into the core principles of reactive systems, the benefits of non-blocking I/O, and the challenges we faced with a reactive approach.

Understanding Reactive architecture style

Reactive encompasses a set of principles and guidelines aimed at constructing responsive distributed systems and applications, characterized by:

  1. Responsiveness:Capable of swiftly handling requests, even under heavy loads.
  2. Resilience:Able to recover from failures with minimal downtime.
  3. Elasticity:Can adapt to changing workloads by scaling resources accordingly.
  4. Message-Driven:Utilizes asynchronous messaging to enhance fault tolerance and decouple components.

One key benefit of reactive systems is their use of non-blocking I/O. This approach avoids blocking threads during I/O operations, allowing a single thread to handle multiple requests concurrently. This can significantly improve system efficiency compared to traditional blocking I/O.
In traditional multithreading, blocking operations pose significant challenges in optimizing systems (Figure 1). Greedy applications consuming excessive memory are inefficient and penalize other applications, often necessitating requests for additional resources like memory, CPU, or larger virtual machines.

Why we discarded Reactive systems architecture from our code?

Figure 1 – Traditional Multi-threading


I/O operations are integral to modern systems, and efficiently managing them is paramount to prevent greedy behavior. Reactive systems employ non-blocking I/O, enabling a low number of OS threads to handle numerous concurrent I/O operations.

Reactive Execution Model

Although non-blocking I/O offers substantial benefits, it introduces a novel execution model distinct from traditional frameworks. Reactive programming emerged to address this issue, as it mitigates the inefficiency of platform threads idling during blocking operations (Figure 2).

Why we discarded Reactive systems architecture from our code?

Figure 2 – Reactive Event Loop


Quarkus and Reactive

Quarkus leverages a reactive engine powered by Eclipse Vert.x and Netty, facilitating non-blocking I/O interactions. Mutiny, the preferred approach for writing reactive code with Quarkus, adopts an event-driven paradigm, wherein reactions are triggered by received events.

Mutiny offers two event-driven and lazy types:

  1. Uni:Emits a single event (an item or a failure), suitable for representing asynchronous actions with zero or one result.
  2. Multi:Emits multiple events (n items, one failure, or one completion), representing streams of items, potentially unbounded.

Challenges with Reactive

While reactive systems offer benefits, we encountered several challenges during development:

  • Paradigm Shift:Reactive programming necessitates a fundamental shift in developers' mindsets, which can be challenging, especially for developers accustomed to imperative programming. Unlike auxiliary tools like the Streams API, the reactive approach demands a complete mindset overhaul.
  • Code Readability and Understanding:Reactive code poses difficulties for new developers to comprehend, leading to increased time spent deciphering and understanding it. The complexity introduced by reactive paradigms compounds this issue.

"Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. ...[Therefore,] making it easy to read makes it easier to write."
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship

  • Debugging Challenges:Debugging reactive code proves nearly impossible with standard IDE debuggers due to lambdas encapsulating most code. Additionally, the loss of meaningful stack traces during exceptions further hampers debugging efforts.Increased Development and Testing Efforts:The inherent complexity of reactive code can lead to longer development cycles due to the time required for writing, modifying, and testing.

Here's an example of reactive code using Mutiny to illustrate the complexity:

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));
Copy after login

Perspectives futures – Projet Loom et au-delà

Le projet Loom, un développement récent de l'écosystème Java, promet d'atténuer les problèmes associés au blocage des opérations. En permettant la création de milliers de threads virtuels sans modifications matérielles, Project Loom pourrait potentiellement éliminer le besoin d'une approche réactive dans de nombreux cas.

"Le projet Loom va tuer la programmation réactive"
Brian Goetz

Conclusion

En conclusion, notre décision de s'éloigner du style d'architecture réactive pour adopter une approche pragmatique de la maintenabilité à long terme de notre projet. Bien que les systèmes réactifs offrent des avantages potentiels, les défis qu'ils ont présentés à notre équipe l'emportaient sur ces avantages dans notre contexte spécifique.

Il est important de noter que ce changement n'a pas compromis les performances. Il s'agit d'un résultat positif, car il démontre qu'une architecture non réactive (impérative) bien conçue peut fournir les performances nécessaires sans la complexité associée à l'architecture réactive dans notre cas.

Alors que nous regardons vers l'avenir, l'accent reste mis sur la création d'une base de code non seulement fonctionnelle, mais également facile à comprendre et à maintenir pour les développeurs de tous niveaux d'expérience. Cela réduit non seulement le temps de développement, mais favorise également une meilleure collaboration et un meilleur partage des connaissances au sein de l'équipe.

Dans le graphique ci-dessous, l'axe Xreprésente la complexité croissante de notre base de code à mesure qu'elle évolue, tandis que l'axe Yreprésente le temps requis pour ces changements de développement.

Why we discarded Reactive systems architecture from our code?

The above is the detailed content of Why we discarded Reactive systems architecture from our code?. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!