Express (Node.js) vs webflux (Spring): confronto delle prestazioni Hello world

Mar 21 2023
Una delle mie serie di articoli popolari è stata il confronto delle prestazioni tra Node.js e Springboot.

Una delle mie serie di articoli popolari è stata il confronto delle prestazioni tra Node.js e Springboot. Ho iniziato la serie confrontando il server HTTP nativo di Node con Springboot (l'articolo è qui ). Poiché l'articolo ha ottenuto un numero record di visualizzazioni, ho ricevuto commenti che:

  1. Un server nativo non dovrebbe essere paragonato a un framework come Spring
  2. Per il confronto tra mele e mele, dovrebbe essere utilizzato il webflux del framework reattivo di Spring invece del threadpool di Spring

Una nota su Spring Webflux

La programmazione reattiva è uno stile di programmazione che si occupa di flussi di dati asincroni ! Un modello di sviluppo che si concentra sull'osservazione dei flussi di dati e sulla reazione ai cambiamenti e sulla loro propagazione. Impari la programmazione reattiva per creare sistemi reattivi: sistemi distribuiti altamente resilienti o microservizi! Spring Webflux è un esempio di programmazione reattiva.

La configurazione del test è la stessa:

  • MacBook M1 con 16 GB di RAM
  • Node.js v19.8.1
  • Primavera 3.0.4 su 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));

Il codice "ciao mondo" di Spring Webflux è stato preso dalla loro documentazione ufficiale:

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);
  }
}

Passiamo direttamente ai risultati.

Express viene spazzato via dalle prestazioni stellari di Spring Webflux. Semplicemente non c'è paragone tra 70k RPS di Spring e 18K RPS di Express. Escludendo un minore utilizzo di CPU e memoria, Express non è da nessuna parte nella competizione.

VINCITORE : Spring Webflux

Un confronto tra Fastify e Spring Webflux è disponibile qui .

Grazie per aver letto! Fatemi sapere eventuali commenti, suggerimenti, ecc.