Aller au contenu

Comment réduire la consommation de RAM dans une application Ruby on Rails ?

Avatar de Matthieu Sadouni
Publié le 13 février 2023 Par Matthieu Sadouni

L’agence Imagile s’est spécialisée dans le développement d’applications web et plus particulièrement dans les applications web métier utilisant Ruby on Rails. Ces applications ont souvent des trafics élevés. Nous établissons toujours avec nos clients un contrat de maintenance technique pour assurer non seulement la sécurité mais également l’optimisation des performances de leurs outils.

Les process Ruby consomment beaucoup de RAM et l’effet est accentué avec le passage sur un serveur web Puma. Chaque process Puma, dont le nombre est déterminé par la variable d’environnement WEB_CONCURRENCY, a une copie de l’application en mémoire et consomme donc autant de RAM que l’application.

C’est de même pour Sidekiq. La consommation de RAM d’un compte est donc grosso-modo (nombre de workers x consommation RAM Application) + consommation RAM Application Sidekiq. Par exemple, pour une application Ruby on Rails à 8 workers et 400 Mo de RAM on arrive à 3,6 Go : (8 * 400) + 400.

Cette consommation vient en grande partie du fait que l’allocateur par défaut, Malloc, gère mal la fragmentation. Les blocs de RAM libérés sont mal réutilisés et la consommation augmente car l’allocateur consomme de nouveaux blocs. Plus l’application tourne longtemps, plus la consommation augmente. Plus elle a d’activité plus elle augmente vite.

Il existe deux solutions « simples » présentées dans les articles suivants :

https://brandonhilkert.com/blog/reducing-sidekiq-memory-usage-with-jemalloc/

« Reducing Sidekiq Memory Usafe With Jemalloc » par Brandon Hilkert @brandonhilkert

https://www.speedshop.co/2017/12/04/malloc-doubles-ruby-memory.html

« Malloc Can Double Multi-threaded Ruby Program Memory Usage » par Nate Berkopec (@nateberkopec)

Nous avons opté pour l’utilisation de jemalloc car il est disponible sur notre serveur et est recommandé dans les articles.

Pour l’utiliser il suffit de déclarer une variable d’environnement LD_PRELOAD avec le chemin vers la bibliothèque jemalloc :

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2

On peut s’attendre à une réduction entre 25% et 50% selon les projets.

Nous avons appliqué cette solution aux applications web Ruby on Rails dont nous avons la charge. Voici deux graphiques montrant les gains obtenus :

Pour surveiller la consommation, nous avons l’habitude d’utiliser htop en ligne de commande sur le serveur et NewRelic.

Prêt à travailler avec nous ?

Contactez-nous, ou venez nous rencontrer pour discuter de vos projets.