Il y a 2 semaines · 15 minutes · Back, Cloud

Serverless vs Micro-Service avec infrastructure « maison »

Introduction

Aucune infrastructure à gérer, telle est la promesse des architectures serverless et services managés.

Deux solutions d’architectures différentes sont comparées ici au travers d’un réel besoin client rencontré en mission.

Une architecture « classique » organisée en micro-services et dont l’infrastructure est à la main du client et une architecture serverless / services managés AWS implémentée lors d’une mission.

Afin de faciliter la comparaison, la solution classique est hébergée sur AWS et utilise le service EC2 sans l’aide de service managé.

Besoin client

Le besoin qui va nous servir d’exemple tout au long de l’article consiste à acquérir une fois par jour des points d’intérêts (POI), à les transformer et les mettre à disposition dans un moteur de recherche afin que la partie front (une carte routière) les récupère pour les afficher.

L’hétérogénéité des POI en entrée est élevée car les partenaires fournisseurs sont divers (Booking, Accor, Airbnb pour les plus connus). Une phase de mapping s’impose afin de convertir le format de chaque fournisseur en un format commun sur lequel seront appliquées toutes les règles de gestion. Pour n’en citer qu’une, qui est d’ailleurs la plus impactante niveau code, un rapprochement est appliqué entre les POI des différents fournisseurs. En effet, un POI peut être présent dans le catalogue de plusieurs partenaires. L’enjeu métier est de constituer une seule entrée dans le système qui sélectionne les informations les plus pertinentes.

L’étape finale consiste à indexer les POI dans un moteur de recherche pour les rendre accessibles. Les recherches effectuées sont essentiellement géographiques ou des filtres sur les prix, les équipements et le nombre d’étoiles des hôtels. La volumétrie totale des POI est supérieure à 1 million d’éléments.

Le traitement fonctionnel peut se schématiser ainsi :

  • Etape 1 : Collecte des POI auprès des partenaires
  • Etape 2 : Mapping & validation de surface
  • Etape 3 : Stockage et rapprochement des POI entres les partenaires
  • Etape 4 : Indexation dans le moteur de recherche

D’un point de vue technique, ce besoin se traduit par la mise en place de quatre services distincts :

  • Un service de collecte de données des différents partenaires ;
  • Un service de mapping et de validation. Les données sont uniformisées au format du client ;
  • Un service d’insertion en base de données ;
  • Un service d’indexation dans le moteur de recherche.

Solution 1: Micro-services et infrastructure « maison »

Partie applicative

L’architecture applicative pour le besoin est simple. Tout s’organise autour d’un bus de messages (ici RabbitMQ). Ce bus permet de rendre nos services indépendants et permet également l’interruption d’un service sans perte de données. En effet, les messages sont persistés dans le bus. Si un service tombe, les messages lui étant destinés seront stockés dans RabbitMQ. Ces messages seront remis au service quand celui-ci sera de nouveau disponible.

Le scaling de nos services sera également facilité. Lorsqu’un nouveau nœud est mis en place, il se connectera automatiquement au RabbitMQ. Ce dernier lui distribuera donc des messages comme aux autres nœuds.

Les services sont développés sur une base Node.js. La base de données choisie est MongoDB, une base orientée document. Un Elasticsearch est également présent.

Enfin, les messages générant des erreurs sont dirigés dans une DLQ dans RabbitMQ. Pour rappel une DLQ ou Dead Letter Queue est une file dédiée où seront envoyés tous les messages ayant générés une erreur (technique ou fonctionnelle) pour analyse et / ou retraitement ultérieur.

Nous sommes donc en présence d’une architecture applicative micro-services des plus classiques.

Partie infrastructure

Lors de la mise en place d’une architecture « classique », la partie infrastructure n’est pas à négliger. La tolérance à la panne et la sécurité sont des points importants à surveiller.

C’est pourquoi dans notre proposition l’ensemble des instances sont placées dans des subnets privés (les Avalaibility Zone sont volontairement masquées sur le schéma).

Les instances EC2 sont également placées dans des autoscaling groups afin de perinsertion et une ré-instanciation automatique des briques utilisées en cas de défaillance.

Les outils RabbitMQ, Elasticsearch et MongoDB étant dans des autoscaling groups, leurs IPs sont dynamiques. Afin de faciliter leur utilisation par les services Node.js, des Elastic Load Balancer (ELB) sont placés devant et font office de VIP.

Enfin, l’application ne s’exécutant qu’une fois par jour, il est possible grâce aux autoscaling groups d’AWS de démarrer les machines au moment voulu de l’exécution. Ceci permet une réduction de coût et évite d’avoir des instances tournant dans le vide 90 % de la journée.

Côté provisioning deux solutions sont possibles avec AWS :

  • Packager une AMI avec l’ensemble des outils nécessaires déjà installés. Une fois l’instance démarrée, elle est prête à l’emploi,

  • Utiliser une AMI de base et configurer la machine une fois démarrée avec des outils tel Ansible.

Le duo CloudFormation / Ansible est un bon moyen pour provisionner et configurer facilement une infrastructure AWS.

Problématiques liées à l’infrastructure

La mise en place d’une infrastructure a forcément un coût. Au développement des services applicatifs s’ajoute celui des scripts Ansible et CloudFormation. Les templates CloudFormation dans une infrastructure maison sont plus conséquents que dans une architecture serverless. Ceci est d’autant plus vrai quand aucun service managé n’est utilisé. Les configurations bas niveau compliquent également ces templates.

Une fois en production cette infrastructure doit être monitorée afin de réagir aux potentiels problèmes. Grâce à la mise en place d’autoscaling group, si une instance tombe, elle sera ré-instanciée automatiquement.

De même, le service Auto Scaling permet de gérer une montée en charge de l’applicatif. Néanmoins, avec les contraintes posées sur le nombre d’instances maximum par groupe, ce service ne permettra pas d’absorber une très forte montée en charge. La configuration devra être affinée en fonction des besoins.

Les mises à jour des systèmes et des outils sont également à la charge des équipes.

Avantages liés à l’infrastructure

La mise en place de sa propre infrastructure n’a pas que des inconvénients. Que cela soit sur EC2 ou sur son propre datacenter, la main mise sur les outils installés est totale. Le paramétrage peut être affiné autant que nécessaire là où les services managés imposent des contraintes fortes dans la configuration.

Les dernières versions d’outils arriveront avec du retard le temps d’être intégrés dans les services managés alors qu’il est possible d’en bénéficier soi-même sur une instance (Node.js 7 par exemple).

L’architecture applicative est également plus souple et ne doit pas s’adapter au catalogue de services du provider de cloud.

Dans notre exemple, c’est l’architecture logicielle qui a construit l’infrastructure et non l’inverse.

Enfin, un autre avantage est qu’il sera facile de sortir de l’infrastructure AWS pour revenir à une infrastructure interne ou bien migrer vers un autre provider de cloud. Seule la partie infrastructure devra être retouchée, la partie applicative étant normalement non impactée par ce changement.

 

Solution 2 : Serverless & services managés

Ici le principe est de gérer le moins de serveurs possible en s’appuyant au maximum sur les services managés fournis par AWS. Les choix de la solution et des technologies vont de fait être influencés par l’offre AWS.

Choix des technologies

Compute

Le code métier est développé en Node.js. Chaque étape est un microservice implémentant les diverses règles de gestion nécessaires au bon fonctionnement de l’application. Pour l’exécution, Lambda est un parfait candidat car il permet de se focaliser uniquement sur le code fonctionnel et non pas sur les problématiques d’installation, de dimensionnement d’infrastructure, de montée en charge, etc.

Ce choix est d’autant plus judicieux que le traitement de chaque message est court (de l’ordre de quelques secondes) et que l’application fonctionne uniquement quelques heures par jour.

Base de données du référentiel

Le catalogue de services AWS propose différents types de bases de données allant du relationnel (Oracle, Aurora, MySQL, PostgreSQL, SQL Server, MariaDB) au NoSQL (DynamoDB) en passant par des clusters de cache (Redis, Memcached). Le choix s’est arrêté sur la base relationnelle MySQL qui dispose de fonctionnalités JSON facilitant le stockage et la manipulation des POI. En d’autres termes, certaines données de référence sont dans des tables tandis que le contenu des POI est stocké directement en format JSON dans une colonne.

Toutes les bases de données relationnelles proposées par AWS sont incluses dans le service Relational Database Service (RDS). Il facilite l’installation, l’administration (backup, restauration) et la haute disponibilité en proposant nativement un déploiement multi-zones de disponibilité. Toutes ces fonctionnalités sont activables en quelques clics dans la console, dans CloudFormation, dans le SDK ou la CLI.

Moteur de recherche

Le choix du moteur de recherche n’est pas aussi riche que pour les base de données. Deux services managés sont proposés : CloudSearch et Elasticsearch Service. Le premier est propriétaire et entièrement managé par AWS. Le second, open-source et développé par la société Elastic.co, est moins managé. Bien qu’il faille un peu plus de configuration et d’intégration, notamment sur le scalling, les backup et les restaurations, Elasticsearch Service est retenu car le client souhaite utiliser des technologies standard du marché.

Infrastructure

Une fois les briques logicielles définies, il reste à les intégrer entre elles pour produire la chaîne de traitement.

Communication entre les étapes

Chaque étape métier (collecte, mapping, stockage, indexation) est développée dans une Lambda qui fait office de micro-service. La communication entre les micro-services est assurée grâce à des files SQS. AWS ne proposant pas le déclenchement de Lambda sur les files SQS, il a fallu développer une Lambda de polling pour lancer le traitement. Hormis cette « tuyauterie » interne, la manipulation de SQS est facile grâce au SDK JavaScript. Bien qu’utilisant les services managés AWS, les appels RDS MySQL et Elasticsearch se font à l’aide des SDK officiels des produits.

Reprise

Pour l’analyse et la reprise sur erreurs, les POI non traités sont envoyés dans des Dead Letter Queue (DLQ) SQS. Ce mécanisme est inclus automatiquement dans la configuration d’une file SQS (Use Redrive Policy).

Monitoring

Le monitoring et l’alerting sont délégués à CloudWatch. Sur chaque DLQ est positionnée une alarme relative au nombre de messages présents. Trop de messages simultanés indiquent une erreur inhabituelle dans le traitement.

Les métriques d’Elasticsearch (espace disque, nombre de documents, nombre de nœuds, CPU, mémoire…) sont remontées automatiquement dans CloudWatch. A l’instar des DLQ elles peuvent aussi faire l’objet d’alarmes. Le service RDS propose les mêmes fonctionnalités.

CloudWatch est doublement intéressant car il fournit un service de monitoring et d’alarme intégré avec SNS (Simple Notifications Service). Au déclenchement d’une alarme il est possible de :

  • Exécuter une lambda
  • Envoyer un SMS
  • Appeler un webhook HTTP ou HTTPS
  • Envoyer un email

Petit plus, Cloudwatch s’interface avec les outils traditionnels de supervision tels que Grafana ou Elasticsearch/Kibana.

Elasticité

Avec AWS Lambda, la modulation de l’infrastructure en rapport à la charge est automatique. AWS instancie plus de lambdas quand le nombre de requêtes augmente et en retire s’il diminue. Attention, par défaut tout compte est limité à 1000 exécutions parallèles. Néanmoins une simple demande au support d’AWS suffit à augmenter ce plafond.

Pour MySQL, MariaDB et PostgreSQL, Amazon RDS supporte les réplicas en lecture en utilisant la réplication asynchrone native de ces moteurs. Les réplicas en lecture fonctionnent comme une instance de base qui n’ autoriserait que des connexions en lecture seule. Cependant dans notre cas d’utilisation la base est fortement sollicitée en écriture et peu en lecture. Seule une scalabilité verticale convient. Le levier se situe dans le choix du type d’instance (db.t2.large, db.r3.2xlarge, db.m4.xlarge…) qui peut intervenir n’importe quand, au prix d’une interruption de service de quelques minutes.

Le service Elasticsearch n’est pas automatiquement élastique car le nombre de nœuds du cluster n’est pas géré automatiquement par AWS. Il est cependant possible de mettre à l’échelle le cluster via un appel d’API ou en quelques clics dans la console.

Avantages liés au cloud

AWS fournit une solution complète et homogène pour gérer un projet de bout en bout. Du calcul au stockage en passant par le monitoring tous les outils sont à disposition. Bien que la création d’une infrastructure soit facilitée, une certaine expertise est recommandée pour obtenir une architecture pérenne, sécurisée et performante.

Avec Lambda (AWS), Functions (Azure), les providers de Cloud surfent sur la vague serverless dont la promesse est de se focaliser sur le code métier plutôt que dans des sempiternelles considérations opérationnelles (maintenance, patch de sécurité, uptime, mise à l’échelle…).

Comparé à une infrastructure on-premise, l’adaptation au changement et le Time to Market sont déroutants. Besoin de plus de files de messages ? De changer la base de données ? Ou encore d’auditer l’architecture ? Quelques appels d’API suffisent.

Problématiques liées à l’infrastructure

Choisir une architecture basée sur des services managés oriente le choix des briques logicielles. Par exemple sur AWS, si un projet nécessite une base de données NoSQL, la première action sera de regarder si le besoin peut convenir à DynamoDB. De même pour le domaine de la recherche avec Elasticsearch en tant que service. Autre exemple concret, que nous avons vu dans le cas fonctionnel de cet article, le broker de message de l’architecture on-premise a été remplacé par du SQS pour simplifier la mise en oeuvre et l’exploitation.

Ces choix induisent du vendor lock-in. Quid alors de la réversibilité ?  Sur ce point deux écoles s’opposent :

  • Accepter le vendor lock-in : la reversibilité n’est pas à penser à priori au risque d’utiliser le plus petit dénominateur commun à toutes les plateformes, à savoir du IaaS et de se priver ainsi de tous les avantages des services managés. La réversibilité doit être abordée en temps voulu pour prendre en compte tous les aspects et conduire ainsi à un véritable projet de migration.

  • Refuser le vendor lock-in : la réversibilité doit être pensée dès le départ pour ne pas s’enfermer sur une plateforme. Entre la rédaction du document de réversibilité adéquat et l’intégration manuelle de différentes briques pour pallier la non utilisation de services managés, cela demande plus de travail.

Conclusion

Il est difficile de comparer les deux solutions tant le choix de l’une ou de l’autre va impacter l’ensemble de l’architecture. Ceci est vrai d’un point de vue infrastructure bien entendu mais également sur la partie code.

Comme nous l’avons vu, une architecture serverless avec services managés ne signifie en aucun cas « sans infrastructure ». S’il est vrai que les problématiques machines sont déléguées à l’hébergeur, il n’en reste pas moins nécessaire d’avoir une bonne maîtrise des services managés utilisés.

Ces services ont par ailleurs un impact fort dans le code de l’application. La panoplie d’outils offerte est également limitée à ceux proposés par l’hébergeur (ici AWS).

D’un autre côté, une architecture micro-services avec une infrastructure maison offre une plus grande souplesse dans le choix des outils mais aussi dans l’articulation des micro-services de l’architecture logicielle. La contrepartie de ce choix est l’obligation de gérer soi-même l’infrastructure. Si AWS offre de multiples services pour simplifier ces phases (autoscaling automatique, provisioning de machines simple), la mise en place et la maintenance de l’infrastructure maison a un coût non négligeable dans la conception de l’application mais aussi dans sa vie en phase de production.

Si une équipe possède déjà des Ops (administrateurs système) expérimentés et que la visibilité sur la charge à venir est suffisante, le choix d’une infrastructure maison peut être pertinent.

A contrario, si le vendor lock-in n’est pas un point de blocage, si l’équipe a peu de bande passante pour le développement d’une infrastructure et si la charge attendue sur l’application est inconnue, alors une architecture basée sur du serverless et des services managés est un choix pertinent. Celui ci permettra de sortir plus rapidement l’application et de gagner en sécurité sur la montée en charge.

Enfin, et c’est sans aucun doute un choix pertinent sur des applications de plus grande ampleur, un mix des deux mondes est tout à fait possible et permettra d’avoir une infrastructure souple sur certaines parties et totalement maîtrisée sur d’autres.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *