Fastify (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.

Avec cet article, je continue à aborder le point numéro 2. Cette fois, je vais comparer Spring Webflux avec le framework fastify de Node.js. Pourquoi Fastifier cette fois ? Parce que Fastify est assez rapide par rapport à Express. Les résultats sont difficiles à prévoir. Découvrons qui gagne cette fois.

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 Fastify from "fastify";
const fastify = Fastify({ logger: false });

fastify.get("/", () => {
  return "Hello world!";
});

fastify.listen({ port: 3000 });

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.

Contrairement à Express, Fastify est capable de concurrencer Springboot avec Webflux, mais perd en RPS et autres mesures de latence. Fastify est capable de marquer des points sur l'utilisation du processeur et de la mémoire.

GAGNANT : Spring Webflux

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