Scaler une infrastructure AWS 2/2 : le modèle

Scale-Out in the Matrix

Comment scaler une infrastructure AWS (Amazon Web Services) ? Je vais décrire dans cette deuxième partie de l’article le modèle de l’architecture et les composants techniques sous-jacents à adopter afin de mettre en place une infrastructure scalable. Nous aborderons tout particulièrement le sujet de l’optimisation de l’accès aux données dans les architectures de type scale-out propices à la distribution, autant au niveau du modèle de données que des couches basses pour l’optimisation des I/O. Nous verrons également les concepts de développement à privilégier tel que le stateless dans la plus pure tradition REST. Je terminerai par quelques trucs et astuces en fin d’article. Le but est de vous permettre de constituer et d’optimiser votre infrastructure en comprenant le fonctionnement des outils proposés par Amazon pour en tirer le meilleur parti.

Le scale-out
Scale-Up in Ghost BusterLe scale-out est à opposer au scale-up : ce dernier correspond à l’augmentation dynamique des ressources d’un serveur donné (ajout de RAM ou de CPU) à la volée. Ainsi l’application continue à s’exécuter sur une même machine dont le potentiel à augmenté. Le scale-out, lui, pour répondre à la montée en charge d’une application propose d’augmenter le nombre de serveurs. Au final, le potentiel global de l’infrastructure augmente aussi, mais est réparti entre plusieurs serveurs. Cela implique que l’application supportée sur le serveur ait été pensée en termes de distribution, c’est à dire qu’elle puisse s’exécuter en parallèle sur plusieurs serveurs sans que cela n’en corrompe la logique métier ou ne pose des problèmes d’accès aux ressources (qui doivent alors être disponibles via le réseau et non en local sur un serveur donné par exemple).

Le scale-out, c’est un peu l’agent Smith de Matrix. Pour le scale-up, pensez plutôt au gentil bibendum de Ghost Buster !

Stateless
Le meilleur moyen d’obtenir une application facilement distribuable et performante est de la penser en mode stateless. C’est à dire que c’est la requête du client qui doit contenir l’ensemble des informations qui vont permettre le traitement de ladite requête côté serveur, soit via un cookie ou bien via les paramètres de l’URL. Quand cela est possible il faut privilégier cette approche à tout prix par rapport au mode stateful dans lequel la partie serveur doit maintenir un contexte pour chaque client afin de pouvoir résoudre sa requête. La conception stateless fait partie des grands concepts du REST. A ce sujet, je ne peux que vous conseiller de lire cet excellent article sur REST de Jean-Paul Figer dans lequel vous pourrez comprendre toute la simplicité et la puissance du style.

Si vous êtes obligés de gérer du stateful, il vous faudra utiliser un cache réseau, tel que Memcached, pour partager les contextes entre vos différents serveurs. N’envisagez pas la formule cache local et sticky session, car vous aurez du mal à bénéficier d’une répartition fluide au niveau de votre load balancing. N’envisagez pas non plus un cluster qui communique en multicast car le réseau Amazon ne permet pas d’en faire… Ou bien alors il faudrait que tous les serveurs communiquent en unicast avec une gateway qui s’occupe de la redistribution des communications… Vous êtes sûr que vous ne préférez pas du stateless ? ;ob

La mise en place d’applications stateless n’est pas arrivée avec le Cloud Computing et les AWS, en revanche ne pas penser dans ce sens, vous empêcherait de bénéficier de tout le dynamisme et la souplesse proposés par ces services.

Optimisation de l’accès aux données
L’optimisation de l’accès aux données passe par 2 éléments :

  • Le modèle de données et l’architecture logicielle que l’on retrouve dans les architectures scalables, que l’on soit sur une infrastructure AWS ou non.
  • La gestion des I/O que l’on peut optimiser, notamment via une utilisation approfondie des AWS.

Le modèle scalable
Cela pourrait faire l’objet d’un article à part entière, mais correspond à un modèle assez classique au sein des applications de type casual gaming ou bien plus généralement liées à des applications basées sur les graphes sociaux ou bien centrées sur une notion métier forte en particulier.

Pour résumer, 2 méthodes de stockage de données :

  • Un stockage de ce que l’on peut appeler le méta-modèle, qui n’a pas vocation à être distribué, basé sur une base relationnelle (même si essentiellement utilisée sous forme d’accès clé-valeur) structurée, indexée, contenant les informations générales de chaque utilisateur (dans la cas d’une application sociale, avec les informations nom, top score, gains de la veille, …), essentiellement accédées en lecture et dont il est possible d’alléger la charge via un Memcached en frontal. Il est donc possible d’effectuer des requêtes ensemblistes de type SQL et ainsi de récupérer des informations via l’utilisation de clauses (WHERE). Cette base peut être un MySQL ou un PgSQL par exemple. Je vous invite à lire ce comparatif très intéressant de Guillaume Plessis entre l’utilisation de MySQL installé sur un EC2 et l’utilisation du service RDS (Relational Database Service) d’Amazon. Je ne trahirai en rien le suspens en vous disant que la base de données c’est une histoire de barbus ! :o)
  • Un stockage pour les données plus volatiles (comme les données de jeu, …), avec un fort rapport écriture/lecture, difficilement cachables, et pour lesquelles il faut opter pour une réelle solution de stockage structurée non relationnelle de type clé-valeur (NoSQL / Not only SQL diront certains), permettant ainsi de distribuer facilement les données sur X serveurs. On peut citer un nombre certain de candidats : Redis, Tokyo Tyrant/Tokyo Cabinet, MemcacheDB, … Et également les nouveaux modèles peer to peer tels que Cassandra, …
Tokyo Cabinet

Tokyo Cabinet

En l’occurrence, Tokyo Tyrant / Tokyo Cabinet est une solution que j’ai mise en place et qui me semble bonne. C’est un couple gérant respectivement les requêtes à partir de serveurs distants (interface réseau) et les accès au système de stockage. 6 APIs sont disponibles afin de stocker les données :

  1. On memory Hash,
  2. On memory B+tree,
  3. File Hash,
  4. File B+tree,
  5. Fixed-length Array,
  6. Table.

Chacune d’entre elles a ses propres spécificités et répond à des besoins particuliers en termes de performances et de fonctionnalités.

Au niveau performances, outre ses performances naturelles, il a l’avantage, notamment, de ne pas gérer l’authentification (standard chez les systèmes de stockage clé-valeur, la sécurité est censée être assurée au niveau réseau pour les accès au système de stockage et au niveau applicatif pour les accès à la donnée – pour ne récupérer que ce qui vous concerne), ce qui allège le nombre d’accès (pas besoin de requêtes d’authentification) par rapport à une base de données classique. De plus, pas de gestion d’index lourds à reconstruire (possible cependant sur l’API « Table » de la Tokyo Team), … Est-il nécessaire de préciser que ce qui vous prendra du temps sur l’accès à la donnée via le réseau (entre le serveur web ou applicatif et Tokyo Tyrant) c’est… Le réseau ! Donc dans tous les cas, préférez l’utilisation au niveau client (API) de « mget » (multi get), par exemple, en positionnant en paramètre le tableau de clés que vous souhaitez récupérer, plutôt que d’effectuer N fois un « get » à partir du client, donc N accès réseau. « mget » se résoudra, lui, au niveau de Tokyo Tyrant.

Ces raisonnements appliqués sur cet outil doivent être appliqués à tout stockage de type clé-valeur.

La gestion des I/O
Venons-en à la spécificité des AWS en termes de stockage : les EBS (Elastic Block Store). Les EBS sont des disques réseau optimisés en I/O, faciles à manipuler, permettant d’assurer la durabilité des données qui ne doivent pas être perdues lors de l’arrêt d’un EC2 (volatile). J’ai cependant constaté de manière empirique des écarts de latence : pas énormes, mais sur une application réellement sollicitée, il y a un ressenti. Ce n’est pas rédhibitoire, il faut juste en tenir compte. Si le Load Average de vos serveurs augmente, ce n’est pas forcément le CPU en cause… Pensez I/O ! ;ob

Tout d’abord penser striping, donc RAID0. Pas besoin de mirroring (RAID1), la durabilité des EBS est déjà assurée par Amazon, de manière transparente, par réplication réseau : tirons parti de ce service et concentrons nous sur le striping. Pensez également à répartir les écritures des différents fichiers physiques (données, updates logs, …) sur différents disques (dans le cas d’outils utilisant des update logs, et c’est le cas pour MySQL et Tokyo Tyrant par exemple, pensez à bien paramétrer leur taille). C’est ce qui permet d’avoir les meilleures optimisations. Ensuite, choisissez bien votre système de fichier par rapport à votre outil (EXT3, XFS, …) et pensez aux options de montage (noatime, nodiratime, …). Finalement vérifiez bien le scheduler/ordonnanceur par défaut sur les instances EC2 que vous démarrez : par défaut, il s’agit de l’ordonnanceur NOOP (requêtes I/O dans une simple file FIFO). Envisagez quelque chose de plus performant comme CFQ (Completely Fair Queuing) par exemple… Enfin je dis ça, mais cela dépend toujours de la couche logiciel au-dessus et si et comment elle gère les priorités : dans cet exemple (qui n’est pas sur EBS) sur MySQL Performance Blog, il apparaît que les ordonnanceurs NOOP et DEADLINE peuvent être de meilleure facture pour améliorer les I/O InnoDB. Comme quoi, il faut quand même mieux tester dans son propre cas ! ;ob

Logical Volume Management

Logical Volume Management

Un autre outil que j’ai utilisé avec les EBS et qui fonctionne très bien est LVM2 (Logical Volume Management, version 2). Je ne l’ai pas utilisé dans le cadre d’une architecture avec un nombre élevé d’IOPS (I/O operations Per Second) et n’ai donc pas testé les possibilités de striping (RAID0) offertes par l’outil. En revanche, je l’ai utilisé dans le cadre d’une infrastructure nécessitant de pouvoir supporter des augmentations conséquentes du volume de données et ceci sans interruption de service. L’opération de snapshot d’un EBS et de recréation du volume est trop longue. LVM est la solution, puisque cette couche d’abstraction permet de gérer des volumes logiques de manière indépendante des ressources physiques : il suffit de lever une nouvelle ressource EBS (une ligne de commande), de l’associer à l’instance EC2 (une autre ligne de commande) et d’ajouter cette ressource au pool de ressources LVM. Il suffit alors d’agrandir le volume logique (toujours transparent et sans arrêt du service), puis d’étendre le système de fichiers. C’est la dernière opération (qui est commune avec celle de la recréation du volume EBS) qui peut nécessiter d’arrêter le service quelques instants (une dizaine de secondes). A noter qu’il est possible d’étendre son système de fichiers à chaud avec EXT3, personnellement, je préfère une interruption de service de quelques secondes sur ce genre d’opérations très courtes mais cruciales. ;ob En prime, il est facile de d’effectuer des backups sur un système LVM qui propose une option de snapshot différentiel que l’on peut monter comme un volume logique indépendant : lorsqu’il y a une modification sur le volume origine, la valeur initiale est copiée dans le volume snapshoté, donc on peut snapshoter des volumes importants sur un espace réduit car seule la fréquence de modification est importante. Vous pourrez trouver de plus amples informations sur LVM2 et EBS en consultant ce très bon article de Laurent Roux.

Tous ces exemples, pour montrer que les EBS sont une ressource très intéressante : il faut les considérer tout d’abord comme un moyen d’assurer la durabilité des ressources importantes avant de considérer l’aspect performance. En effet, la performance n’est pas forcément meilleure sur un EBS que sur les disques locaux d’une instance EC2 (Cf. un test simple et intéressant de Charles-Christian Croix ou bien encore des tests un peu plus complexes que vous pourrez retrouver en tapant « performance ephemeral disk ebs volume raid » dans Google, il y en a un certain nombre de très intéressants et je dois avouer que j’ai du mal à faire mon choix ;ob). Cependant, quand on prend le parti d’assurer la durabilité de ses données et donc d’utiliser un EBS (qui, pour ceux qui connaissent, est comparable à un LUN sur un SAN), il y a divers moyens d’optimiser leur performance.

Il est à noter que les utiliser pour répartir les fichiers (et donc les I/O) sur plusieurs disques EBS peut être une solution de performance pure.

A noter tout de même que la bande passante de l’EC2 est forcément limitant arrivée à un certain seuil : ajouter des EBS est intéressant pour lisser les écarts de variance (en RAID0) ou bien pour optimiser le débit, mais il n’en reste pas moins que si vous ajoutez plusieurs EBS à votre instance EC2 et qu’ils sont tous sollicités fortement… C’est la bande passante de l’EC2 qui bloque. Il va falloir ajouter un nouvel EC2 (scale-out pour augmenter les ressources, en l’occurrence la bande passante), lui attacher de nouveaux EBS (n’oubliez pas qu’un EBS ne peut être attaché qu’à un et un seul EC2) et distribuer la donnée dessus (sharding).

Dans tous les cas, la manipulation des EBS est aisée et cette souplesse est un atout.

Tips & tricks
Cette dernière partie regroupe quelques trucs et astuces.

Alias & IPs
Pensez sur une infrastructure AWS à positionner des alias correspondant aux IPs privées de vos instances dans le fichier des « hosts », que vous pouvez déployer ensuite via Puppet pour plus de réactivité vu que les IPs sont « variables » (lorsque vous arrêtez une instance et que vous en redémarrez une juste après, vous ne conservez pas la même IP). L’utilisation du fichier « hosts » évite des résolutions DNS internes chez Amazon.

CDN & S3 Headers
Pour les CDN (Content Delivery Network) que vous utilisez obligatoirement dans une architecture scalable, pensez à utiliser S3 afin de mettre à disposition les images et autres contenus statiques. Inutile de maintenir un serveur Web à cette seule fin, S3 est là pour ça pour un coût minime.

Pensez également dans certains cas, où votre trafic est plus modéré et où vous ne souhaitez pas passer par un CDN (pour des questions de coût par exemple ;ob), que vous pouvez toujours optimiser la gestion de vos ressources sur S3 en utilisant les méta-données attribuées aux dites ressources sur S3, en positionnant, par exemple, les headers de type Cache-Control ou Expires. Vous pouvez visualiser ces méta-données via le nouvel onglet S3 de la console d’administration Amazon.

Backups… What else ?
S3 est également la solution pour les backups. Je n’ai pas trouvé d’outils intégrés satisfaisants pour cette tâche : j’utilise simplement un outil en ligne de commande « s3cmd » afin de stocker mes backups. J’ai intégré cet outil dans des tâches Capistrano appelées par cron. Très simple d’utilisation, s3cmd permet de consommer les services de S3 et offre la possibilité de transférer les données en HTTPS et également de les stocker sous un format crypté.

Conclusion
Il y aurait encore beaucoup de choses à dire sur ce sujet, mais ce sont à mon avis les principales, en tout cas par rapport à l’utilisation des services mis à disposition par les AWS. Ce qu’il en ressort, c’est :

  • Le stateless et REST de manière générale, sont d’autant plus adaptés aux AWS qu’ils permettent de distribuer aisément la charge sur une infrastructure s’adaptant à la montée en charge sur un modèle scale-out.
  • L’accès aux données est toujours le goulet d’étranglement des applications distribuées devant scaler. Il s’agit de travailler à ce niveau le modèle de données et de tirer parti des systèmes de stockage adéquates :
    • Technologies SQL pour les méta-données pouvant nécessiter du requêtage ensembliste et de la mise en  relation, tout en utilisant au maximum un cache réseau pour les informations avec un fort ratio lecture sur écriture.
    • Technologies NoSQL / Not only SQL / clé-valeur pour les informations pouvant être accédées par une clé unique, et ainsi bénéficier de la distribution inhérente au scale-out.
  • Penser finalement aux couches basses en sélectionnant convenablement le système de fichiers et l’ordonnanceur. Pensez également RAID (striping) et LVM (extension de volume et snapshot différentiel) pour tirer parti de la souplesse d’utilisation des EBS et répartition des I/O sur différents devices (en prenant toujours garde à votre bande passante, au niveau EC2, qui peut devenir limitant : dans ce cas ajouter une ou plusieurs instances EC2 pour gagner en bande passante et distribuer – sharder – la donnée sur de nouveaux EBS).

J’espère que ce deuxième volet de mon retour d’expérience sur la scalabilité des infrastructures AWS vous aura intéressé.

Frédéric FAURE @Twitter @Ysance

Un commentaire pour Scaler une infrastructure AWS 2/2 : le modèle

Répondre

 

 

 

Vous pouvez utiliser ces balises HTML

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>