Express (Node.js) vs webflux (Spring) : Comparaison des performances Hello world

Mar 21 2023
L'une de mes séries d'articles populaires a été la comparaison des performances entre Node.js et Springboot.

L'une de mes séries d'articles populaires a été la comparaison des performances entre Node.js et Springboot. J'ai commencé la série en comparant le serveur HTTP natif de Node avec Springboot (l'article est ici ). Comme l'article a obtenu un nombre record de vues, j'ai reçu des commentaires qui :

  1. Un serveur natif ne doit pas être comparé à un framework comme Spring
  2. Pour la comparaison de pommes à pommes, le webflux du framework réactif de Spring doit être utilisé à la place du pool de threads de Spring.

Une note sur Spring Webflux

La programmation réactive est un style de programmation qui traite des flux de données asynchrones ! Un modèle de développement qui se concentre sur l'observation des flux de données, la réaction aux changements et leur propagation. Vous apprenez la programmation réactive pour créer des systèmes réactifs - des systèmes distribués hautement résilients ou des microservices ! Spring Webflux est un exemple de programmation réactive.

La configuration du test est la même :

  • MacBook M1 avec 16 Go de RAM
  • Node.js v19.8.1
  • Printemps 3.0.4 sur Java 17

Node.js

import express from "express";
const app = express();
const port = 3000;

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => console.log("Listening on", port));

Le code "hello world" de Spring Webflux a été extrait de leur documentation officielle :

HelloWorldHandler.java

package hello;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

@Component
public class HelloWorldHandler {

  public Mono<ServerResponse> hello(ServerRequest request) {
    return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
      .body(BodyInserters.fromValue("Hello World!"));
  }
}

package hello;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;

@Configuration(proxyBeanMethods = false)
public class HelloWorldRouter {

  @Bean
  public RouterFunction<ServerResponse> route(HelloWorldHandler helloWorldHandler) {

    return RouterFunctions
      .route(GET("/"), helloWorldHandler::hello);
  }
}

package hello;

import reactor.core.publisher.Mono;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class HelloWorldClient {

  private final WebClient client;

  public HelloWorldClient(WebClient.Builder builder) {
    this.client = builder.baseUrl("http://localhost:3000").build();
  }

  public Mono<ClientResponse> getMessage() {
    return this.client.get()
      .uri("/")
      .exchange();
  }

}

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
    HelloWorldClient helloWorldClient = context.getBean(HelloWorldClient.class);
  }
}

Passons directement aux résultats.

Express est emporté par les performances exceptionnelles de Spring Webflux. Il n'y a tout simplement aucune comparaison entre 70k RPS de Spring et 18K RPS d'Express. À moins d'utiliser moins de processeur et de mémoire, Express n'est nulle part dans la concurrence.

GAGNANT : Spring Webflux

Une comparaison de Fastify avec Spring Webflux est disponible ici .

Merci d'avoir lu! Faites-moi part de vos commentaires, suggestions, etc.