Erlang: cluster ARM Pi2 contre une VM Xeon

Pieterjan Montens
10 min readFeb 26, 2016

--

Ceci n’est pas un jouet

English version - version anglaise (originale)

Nederlandstalige versie - version néerlandophone

En Bref

Un prototype de cluster (un groupe de serveurs, ou encore une grappe de serveurs) ARM à faible coût et à basse consommation prouve qu’il pourrait être une alternative viable à une plate-forme plus traditionnelle pour une application serveur Erlang/OTP existante.

Après l’introduction ci-dessous suit une description des plates-formes utilisées, un petit mot sur l’application qui a servi à les comparer, les graphiques et les observations qui en résultent et une conclusion.

Introduction

La mise sur le marché par AMD d’un processeur ARMv8 64-bit, l’Opteron A1100, à piqué ma curiosité. Les plateformes matérielles sont devenues si puissantes et coûteuses qu’elles nécessitent d’être virtualisées à plusieurs niveaux (processeur, stockage, réseau, …), ajoutant autant de couches de complexité, pour pouvoir les utiliser pleinement. L’idée d’utiliser une plateforme peu onéreuse et extrêmement économe en énergie n’en est que plus rafraîchissante.

Avec les outils et logiciels permettant d’appréhender l’équilibrage de charge, le basculement en cas d’erreur et les autres défis de l’informatique distribuée, cette idée est devenue un prototype au fonctionnement quasi parfait.

Plate-formes de test

Bien que des kits de développement intégrant l’Opteron A1100 sont déjà disponibles, je me suis orienté vers le Raspberry Pi 2 (modèle B) comme étant une solution abordable pour un prototype. Il fait parfaitement tourner l’OS serveur (Debian). Et compte tenu du fait que le processeur ARMv7 32 bits (le même que dans mon smartphone) est d’une architecture assez âgée et lente, qui n’a même pas besoin de dissipation thermique, il s’en sort assez bien.

La réactivité de l’application, tournant sur le cluster Raspberry, était absolument satisfaisante pour une utilisation normale, malgré les faiblesses de la plateforme. Compte tenu des résultats du comparatif, je suis presque convaincu qu’il pourrait gérer notre charge de travail actuelle en production sans trop de peine.

PI2C

Cluster Raspberry PI 2 (PI2C)

Spécifications d’un Raspberry Pi 2 Modèle B:

  • CPU : Cortex A7 quad@950 MHz, 1GB RAM, légèrement surcadencé
  • Stockage : 32GB Samsung EVO+ MicroSD
  • Coût : ~30€
  • Consommation énergique au repos: 3,33w - pleine charge: 4,8w
  • 100 Mbps Ethernet*

Tout le cluster (4 Pi2 en tout: 1 proxy Apache pour la répartition de charge, 3 pour le cluster de l’application) :

  • Coût : ~200 €
  • Consommation énergique au repos: 13w - pleine charge: 18w

*Le proxy Apache, qui dispose de 2 ports Ethernet, agit aussi comme DHCP, DNS, et routeur (NAT) pour les autres membres du cluster, le cluster disposant de son propre réseau.

DevX

Xeon Server

Le visage d’une informatique d’entreprise

DevX est le serveur de développement de l’application, et fonctionne sous un environnement virtualisé VmWare HP BladeSystem avec comme outil de stockage un San StoreVirtual iSCSI, le tout dans une salle climatisée, et ayant de multiples contrats de support matériel 24/7. Spécifications :

  • VM: 2 noyaux 2,4GHz (Xeon E5620), 3 Go de Ram
  • Stockage: iSCSi I50 Go
  • Consommation d’énergie de serveur lame *: 250W (non inclus: le stockage et la climatisation)
  • Coût d’un serveur lame *: environ 5000 € (non inclus: contrats de soutien, le stockage, le boitier de la lame et la climatisation). RCP du processeur uniquement: 391,00 $

*Le coût du serveur et sa consommation électrique devraient être adaptées au nombre de machines virtuelles tournant sur le serveur (6)

L’application de test

l’application utilisée dans ce comparatif est une application serveur issue et utilisée dans le monde réel, la plate-forme e-justice du Conseil d’État Belge. Il est basé sur Erlang/OTP et peut être exécuté à la fois en tant qu’instance unique ou en mode distribué (multiples instances). Le scénario de test utilise des opérations standard offertes par l’application, mais n’est pas représentatif de la façon dont un utilisateur réel agirait (étant beaucoup plus rapide). L’application est également fortement dépendante de la base de données (Mnesia), et donc de la vitesse de son moyen de stockage, ce qui explique pourquoi un simple test de calcul a été ajoutée.

L’application (y compris sa base de données) n’a pas été modifiée, outre une recompilation, pour pouvoir fonctionner sur l’instruction ARM ou sur une plate-forme matérielle avec des ressources limitées. La plupart des défauts mis au jour par le test de charge (par exemple la tendance de l’application à se noyer lorsqu’elle subit un grand nombre de requêtes simultanées) ont déjà été corrigés, mais c’est un sujet pour un autre article.

Considérations particulières sur les deux environnements

PI2C:

+ L’application tourne dans un nœud (un processus) Erlang unique sur chaque membre du cluster;
- Stockage très lent. Impitoyable test lecture et écriture aléatoire : respectivement 1.819 et 855 Ko/s;
- Réseau plus lent et le fait que la BD, Mnesia, doit se synchroniser avec les autres membres du cluster, ce qui amène des retards dus à la surcharge, encore aggravés par le stockage très lent.

DevX:

+Environnement natif sur lequel l’application a été développée;
+ Stockage rapide. Impitoyable test lecture et écriture aléatoire: respectivement 27.577 et 11.062 Ko/s;
+ Instance unique: pas de synchronisation avec d’autres instances;
- L’Application est divisée en 2 nœuds Erlang (serveur mochiweb et cœur de l’application), ce qui ajoute une certaine latence.

Tests comparatifs de performance

Méthodologie d’essai et concepts

Cycle: un seul cycle comporte plusieurs opérations en série tels que la création d’un objet, la navigation, la modification et la suppression. Il reflète ce qu’un utilisateur humain pourrait faire, mais à une vitesse beaucoup plus élevée.

Agent: Un agent exécute des cycles. Une fois un cycle terminé avec succès, un nouveau cycle démarre. Plusieurs agents peuvent être exécutées simultanément. Chaque test commence avec 1 agent et se poursuit en doublant leur nombre jusqu’à atteindre 128 ou 256, en fonction de l’apparition d’échecs suite aux délais d’attente trop élevés.

J’ai utilisé l’outil de test en python multi-mechanize pour exécuter les tests, en générant des requêtes HTTP envoyés au proxy Apache de l’environnement cible. Un test complet dure 120 secondes, et lance tous ses agents (le cas échéant) dans les 10 secondes (ce qui a probablement favorisé DevX).

Test de performance de base

Première comparaison, la performance de base entre les deux environnements, où chacun montre sa force: la vitesse du processeur pour DevX lorsque la charge est basse et l’équilibrage de charge pour PI2C lorsque la charge est haute.

  • Quand il n’y a qu’un seul agent actif, le processeur rapide de DevX a un avantage évident. La tâche ne peut pas être partagée entre les membres du cluster de PI2C, il n’y a donc qu’un seul des 3 processeurs de PI2C qui travaille à un instant donné;
  • Avec seulement 2 cœurs, DevX plafonne (100% de charge) à partir de 4 agents simultanés, tandis que PI2C, avec ses 12 cœurs, ne plafonne qu’à partir de 32. Il améliore sa performance tout au long du chemin, et atteint plus de 70% de la performance de DevX à pleine charge;
  • À 128 agents simultanés, les deux environnements commencent à ressentir des délais d’attente trop élevés: les requêtes prennent trop de temps pour s’exécuter et sont abandonnées;
  • À 256 agents simultanés les scores commencent à être négatifs, ce qui signifie que même le premier cycle de certains agents échoue (ce qui se traduit par un score négatif en raison de quelques particularités du framework de test).

Ce graphique illustre la façon dont PI2C se rapproche de la performance de DevX: le nombre de cycles exécutés par chaque agent reste stable plus longtemps.

  • A partir de 4 agents simultanés, DevX connaît une diminution linéaire de cycles effectués avec succès, réduisant de moitié son score à chaque doublement des agents simultanés;
  • PI2C montre une diminution plus progressive, qui ne devient linéaire qu’à partir de 16 agents simultanés.

PI2C: Influence de la taille de cluster

Chaque ligne du graphique représente PI2C avec à chaque fois un nombre différent de membres actifs (de 1 à 3).

  • Moins il y a de membres dans la grappe, plus l’application est rapide au début du test: il y a moins d’opérations de réplication et de synchronisation de la base de données, ce qui libère des ressources;
  • Une fois passé un certain seuil de charge, l’avantage de la répartition de charge entre en jeu. En d’autres termes: l‘application est scalable (oui, ça se dit).
  • L’augmentation des performances n’est pas linéaire (il ne double pas lorsque la quantité des membres du cluster double) en raison de la perte en performance causée par la réplication de la base de données. Ceci est un comportement connu de Mnesia, et doit juste être prise en compte (tout comme les gens de WhatsApp l’ont fait).

Test de calcul pur

Afin de ne comparer que la puissance de calcul, j’ai ajouté une fonction simple qui génère une fractale de Mandelbrot. Un cycle devient un simple calcul, libérant PI2C de son support de stockage trop lent, lui permettant d’exprimer sans retenue son affolante puissance de traitement.

Diverses configurations d’environnement sont utilisées ici. Un nombre variable d’éléments actifs pour PI2C, et un DevX sous stéroïdes avec un nombre de cœurs doublés.

  • L’augmentation linéaire de la performance démontre l’efficacité de la répartition de la charge entre les membres de la grappe et les noyaux des processeurs (rien d’extraordinaire, ce n’est que du simple calcul);
  • PI2C surpasse DevX à partir de 32 agents simultanés. Pour être certain qu’il ne s’agit pas là d’un goulot d’étranglement inconnu (pc de test, réseau, proxy, …), le même test a été réalisé sur un DevX avec 4 cœurs, doublant ainsi son score: pas de goulot d’étranglement.
  • Notez la meilleure performance de DevX x4 quand il n’y a qu’un seul agent actif par rapport à DevX x2. 4 cœurs ne font pas travailler DevX plus vite, ils est toujours limité à 2,4 GHz: la différence est le code Erlang et l’application répartissant la charge d’une seule requête sur plusieurs cœurs (la programmation parallèle). Cela rend les processeurs ARM avec 8 cœurs ou plus encore plus intéressants.
  • PI2C ne peut répartir les tâches d’une seule requête que sur un unique membre de la grappe. Voilà pourquoi chaque configuration différente a pratiquement le même score lors du test avec seulement 1 agent. Il en est de même quand il y a deux agents actifs pour les deux configurations avec au moins 2 membres.
  • L’augmentation linéaire presque parfaite de la performance en parallèle aux nombre de cœurs ou de membres de la grappe démontre clairement l’efficacité de la scalabilité d’un système Erlang/OTP (rien de neuf, en réalité).

Comparatif des modes de transaction de Mnesia

Ceci est plutôt destiné aux connaisseurs d’Erlang. Mnesia, par le biais de mnesia: activity/2, peut être consulté de 4 façons différentes: avec ou sans transactions, de manière synchrone ou asynchrone. Chaque méthode a ses avantages, et se résume à échanger performance contre stabilité. PI2C à connu quelques erreurs dans les modes asynchrones (tout à fait attendues), causées par des accumulations trop importantes de transactions en attente, jusqu’à ne plus pouvoir garantir que chaque instance disposait des mêmes données (une perte de cohérence).

La différence entre les modes synchrones ou asynchrones est manifestement sans pertinence pour DevX (aucun effort de synchronisation avec d’autres instances n’est nécessaire), tandis que PI2C présente le rendement attendu des différents compromis. Sans le poids supplémentaire des transactions et la synchronicité, en bleu clait, PI2C est même capable d’effleurer le niveau de performance de DevX (avant de descendre en flammes).

  • La seule différence notable pour DevX est entre les opérations «dirty» (sans les transactions) et les opérations transactionnelles (avec verrous de table, rollbacks en cas de panne, …);
  • Le taux d’erreurs de cohérence de la BD de PI2C atteint le 1-pour-100 dans le mode async_dirty et en 1-pour-500 en transaction asynchrone (et aucun dans les modes synchronisés, comme on peut s’y attendre);
  • Dans le cluster il y a une baisse de performance lorsque la synchronicité est appliquée. Cette différence tend à disparaître sous une charge plus lourde, où elle permet d’éviter les surcharges des base de données des nœuds distants et garantit la cohérence de la BD.

Conclusion

Avec une couche de stockage plus rapide, PI2C aurait eu de bonnes chances face à un serveur virtualisé “traditionnel”, pour une fraction des coûts d’utilisation et d’énergie. J’ai omis de le mentionner, mais l’application de test est encore sujet à des goulots d’étranglement en série, des procédés peu ou pas parallélisables, tels que des interactions avec un serveur socket Prolog, qui doivent avoir eu un impact négatif sur la performance du cluster.

Le prototype a été en mesure de démontrer la viabilité et même la performance d’un cluster ARM extrêmement modeste. Je suis convaincu que des puces ARM plus modernes et plus puissantes (ils n’arrêtent pas d’être annoncés), avec des capacités de stockage et de réseau dignes d’un véritable serveur, sont en mesure de justifier leur présence dans une salle de serveur moderne. Leur introduction pourrait annoncer une ère de salles informatiques où les coûts et la consommation énergétique seront mieux maîtrisés et qui, selon l’endroit où on les crée, n‘auraient même plus besoin d’être climatisées.

--

--