Au revoir Rails, bonjour Node.js

Pourquoi sommes-nous passés de Rails à Node.js

Pourquoi donc changer ?

À ses débuts, Doctrine.fr était sous Ruby on Rails. Plus par habitude que par choix, car nous étions tous des amateurs de Rails. Un jour, Tariq KRIM nous a dit : « Les gars, faut passer à Node.js ! »

Node.js est certes à la mode depuis quelques années comme le prouve Google Trends, mais pour autant, une transition valait-elle le coup ?

Google Trends : Node.js dépasse Ruby on Rails en 2013.

Tout d’abord, tout le monde connaît (un peu) de JavaScript. Si vous avez Angular, Backbone ou Ember en front, vous communiquez avec votre serveur en JSON. Ainsi, avoir Node.js sur le serveur évite des conversions permanentes. Un développeur front pourra plus facilement passer en back, et inversement, utile dans de petites équipes. Les employeurs ne s’y sont pas trompés : depuis 2015, les développeurs Node.js sont plus recherchés que les développeurs Ruby on Rails sur Indeed.

Offres d’emploi sur Indeed : Node.js a dépassé Ruby on Rails en 2015.

Un des défauts de Node.js (né en 2009), par rapport à Ruby on Rails (2005), serait sa jeunesse. Néanmoins, la communauté Node est extrêmement active. Résultat : le merveilleux dépôt npm compte depuis 2014 plus de modules que Rubygems.

ModuleCounts : npm (node.js) dépasse Rubygems.org en 2014.

Et sur Stack Overflow, Node.js est depuis novembre 2015 plus débattu que Rails :

Stack Overflow : Node.js dépasse Rails fin 2015 en termes de popularité.

L’avantage de Node.js est surtout sa rapidité : le moteur V8, développé par Google pour Chrome, compile et exécute le JavaScript très rapidement. Surtout, le fonctionnement de Node.js est non bloquant (ou asynchrone), ce qui permet de réaliser un maximum d’opérations en parallèle et accélère le chargement des pages.

Ces dernières années, de nombreuses entreprises ont migré vers Node.js :

Forts de ces enseignements, nous nous sommes dit qu’il serait intéressant de benchmarker Node.js, d’abord sur une partie du site puis de migrer totalement si l’essai était concluant.

Le test de performances

Pour mieux comprendre, quand tout était écrit en Rails, l’application de Doctrine.fr était séparée en 2 serveurs : la partie search qui répond aux requêtes AJAX du navigateur pour les recherches, et celle qui envoie au client toutes les autres pages (HTML, images, scripts, CSS…). Comme les requêtes pour afficher les pages étaient parfois longues en Rails cela permettait aux recherches d’être rapides.

L’idée était dans un premier temps de benchmarker la partie search. Choix naturel, car cette partie ne fait que répondre aux requêtes AJAX en JSON à la partie écrite en AngularJS sur la machine de l’utilisateur.

Résultats du benchmark

Après un jour de travail à la réécriture du search en Node.js, nous avons comparé les performances de Node.js et Rails avec un serveur ayant un CPU et 1 GB de RAM. Avec 50 recherches par seconde, Node.js et Rails arrivent tous les deux à tenir la charge, Rails utilise alors 50% du CPU et Node.js seulement 30%. Mais il est impossible pour Rails de traiter plus de recherches, alors qu’avec Node.js on peut monter à 120 par seconde (46% du CPU utilisé). Au-delà, Node.js plante car il n’y a plus assez de mémoire. Dans tous les cas, le facteur limitant est la RAM et non le le CPU.

Ainsi, avec des machines identiques, Node.js permettrait de servir deux fois plus d’utilisateurs. À l’échelle, cela signifie une division par deux des coûts.

Comment fonctionne Node.js ?

Si on peut économiser autant de RAM c’est grâce au fonctionnement non bloquant de Node.js, bien différent des langages comme Rails.

Dans Rails, quand vous consultez une décision de justice sur notre site, le programme effectue par exemple les opérations suivantes dans l’ordre :

  1. Chercher la décision dans la base de données ;

Pour éviter de bloquer le serveur pendant les phases d’attente (entre 1 et 2 et entre 2 et 3), Rails lance en parallèle différents threads permettant ainsi de répondre à d’autres utilisateurs pendant ces phases d’attente. Mais chaque thread nécessite une quantité importante de RAM.

Node.js procède différemment, vous ne dites pas “fais ceci, puis cela, puis cela” mais plutôt “fais ceci et voilà ce que tu devras faire quand ce sera fini, mais en attendant je n’ai plus rien à te demander”. Cette petite différence, en apparence, signifie que Node.js sait explicitement la différence entre les phases “calcul” (comme 3 et 4) et les phases “attente” (comme 1 et 2). Le programme ci-dessus se réécrit de la façon suivante :

  1. Demander la décision à la base de données et quand elle sera disponible, faire tout ce qui suit :

Pour l’étape 2, Node.js triche et ne réalise pas vraiment l’opération en parallèle. En réalité, il demande les commentaires de la décision à la base de données, voit alors que “là il n’y a plus qu’à attendre” et traite ensuite le contenu car on a indiqué dans le programme que les deux pouvaient être faits en parallèle. Une fois cela fait, il voit qu’il faut que les deux opérations soient terminées et qu’on attende encore la réponse de la base de données (en général plus lente que le traitement du contenu). Node.js peut donc “faire autre chose” en attendant, par exemple traiter une recherche.

Cela a deux avantages :

  • Le chargement est plus rapide pour l’utilisateur ;

Réécriture en Node.js : observations diverses

Nous avons donc décidé de réécrire la totalité du site en Node.js. Lors de la réécriture, j’ai fait les observations suivantes, qui peuvent être utiles si vous migrez aussi de Rails à Node.js :

  • La gestion des erreurs est totalement différente, on ne lève pas d’exceptions à tout bout de champ. À la place, on passe les erreurs au callback. La syntaxe “if (error) return callback(error)” devient un classique, présent partout dans le code.

Conclusions sur notre transition

Grâce au passage en Node.js nous avons gagné :

  • Une division par deux des coûts fixes (plus besoin de séparer les deux parties search et web) ;

[UPDATE 10/06/2016 : Ajout du graphique Stack Overflow]

Inside Doctrine

Stories from the people who build Doctrine

Raphaël Champeimont

Written by

Lead Architect of Doctrine.fr

Inside Doctrine

Stories from the people who build Doctrine

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade