Systèmes distribués: Quand faut-il les construire et comment les faire évoluer? Un guide étape par étape.

Photo par Jeremy McKnight sur Unsplash

Je suis toujours frappé par le nombre de jeunes développeurs qui souffrent du syndrome de l'imposteur lorsqu'ils ont commencé à créer leur produit.

Je comprends. Il existe de nombreux exemples époustouflants de grandes entreprises dotées de systèmes distribués extrêmement complexes capables de traiter des milliards de demandes, de mettre à niveau gracieusement des centaines d'applications sans interruption de service, de récupérer du désastre en quelques secondes, de publier toutes les 60 minutes et de gagner rapidement en efficacité. temps de réponse de partout dans le monde.

Ces attentes peuvent être très lourdes lorsque vous démarrez votre projet. Mais comme beaucoup d’entre vous le savent déjà, la majorité de ces entreprises ont démarré avec un système viable minimal et une pile de technologies très médiocre. La raison en est simple: ils n’en avaient pas besoin au début. Consacrer plus de temps à la conception de votre système au lieu du codage peut en réalité vous faire échouer.

Cet article explique pas à pas comment guider. Je vais vous montrer comment, chez Visage, nous avons démarré avec le système le plus petit jamais construit et construit un système distribué évolutif de base à haute disponibilité. C’est une étude de cas concret pour éliminer vos complexes si vous n’avez jamais eu l’occasion de le faire vous-même.

Lorsque je suis arrivé chez Visage en tant que CTO, j'étais le seul ingénieur. Je ne connaissais rien à la pile de technologies, mais j'ai adhéré parce que j'aimais vraiment l'idée de pouvoir recruter sans recruteurs internes ni service des ressources humaines. C’est l’idée de base de Visage: le crowdsourcing, animé par un grand nombre de recruteurs invisibles travaillant ensemble sur vos rôles, assisté par une intelligence artificielle qui rechercherait le talent le plus approprié pour vous en quelques jours. Ensuite, vous vous engagez directement avec eux, pas d'intermédiaire.

La «foule» dans le crowdsourcing a instantanément déclenché mon cerveau d'ingénieur: beaucoup de personnes vont travailler en même temps, s'attendant à de bonnes performances de partout dans le monde. J'ai aimé le défi.

Mais du point de vue du système, les choses allaient mal, vraiment mal. Voici ce que j'ai trouvé à mon arrivée:

  • Une instance Wordpress compromise exécutant des centaines de plugins obsolètes et défectueux, s'exécutant sur une machine virtuelle sur un serveur partagé
  • Boîtes aux lettres compromises
  • Une tonne de Google Docs et Spreadsheets.

Et c'est parfaitement normal. Encore une fois, il n'y avait pas de membre technique dans l'équipe et je m'attendais à quelque chose comme ça. L'équipe s'était néanmoins concentrée sur une opportunité commerciale et donnait l'impression que le produit fonctionnait comme par magie en faisant tout à la main! (Fais semblant jusqu'à ce que tu y arrives). Et c’est ce qui était vraiment incroyable.

Notre premier système (oui, c'était nul mais ça a fait le boulot)!

Il n’est pas surprenant que ma première tâche ait été de recréer la machine virtuelle, de réinstaller une version mise à jour de Wordpress, de s’assurer que tout le monde change de mot de passe, d’établir une politique de mot de passe et de supprimer des dizaines de programmes malveillants sur les ordinateurs de la société… mais passons maintenant aux considérations relatives aux systèmes.

De Wordpress à une application Web

Lorsque vous commencez à créer un produit, votre premier objectif doit être les données. Les données sont ce qui fait la valeur de votre entreprise. Ce sera ce que vous utilisez tous les jours pour prendre des décisions et ce que vous montrez à vos investisseurs pour démontrer les progrès accomplis.

Vous devez donner un sens à vos données, et les récupérer à partir de sources différentes avec des formats différents va être une énorme perte de temps. Wordpress peut être un très bon choix dans de nombreux cas en faisant gagner beaucoup de temps d'ingénierie, mais pour leurs besoins, l'équipe de Visage a dû installer des plugins sophistiqués qui n'étaient plus maintenus. En conséquence, nous n’avions aucun contrôle sur le modèle de données généré et les données qui ne pouvaient pas correspondre au modèle étaient éparpillées dans des dizaines de documents et de feuilles de calcul.

Par conséquent, à moins qu'un produit ne réponde déjà à 90% de vos besoins, pensez à un modèle de données idéal, puis concevez et mettez en œuvre un produit minimum viable (MVP) capable de contenir toutes vos données.

Alors pensez API. Votre application doit avoir une API, elle sera critique lorsque vous la vendez. Ne mettez pas immédiatement à l’échelle, mais codez pour une évolutivité. Rendez votre API sans état et aussi RESTful que possible, car tout le monde s’attendra à pouvoir l’interroger à l’aide de méthodes HTTP standard.

Nous avons choisi NodeJS dans notre cas, parce que la plupart de notre code ne traiterait que les entrées et les sorties. NodeJS est non bloquant et est livré avec une bibliothèque pratique pour la conception d'API: ExpressJS.

Si vous avez besoin d'un site Web destiné aux clients, vous avez plusieurs options. Tout d'abord, vous pouvez créer une couche dans votre serveur d'applications qui générera vos pages ou vous pouvez créer une application Javascript à page unique qui sera servie par un serveur d'hébergement Web statique.

Chez Visage, nous avons opté pour la deuxième option et avons décidé de créer une application pour les utilisateurs et une autre pour les administrateurs. C'était simplement parce que nous avions des attentes beaucoup plus grandes pour les utilisateurs que ce dont nous avions besoin avec les administrateurs, et nous voulions garder les deux bases de code simples (également, pour des considérations relatives à CORS plus tard). Voici à quoi ressemblait notre système:

Toutes les données en un seul endroit

Déléguez tôt le stockage de données sensibles

Si cela n’est pas critique pour votre entreprise, il n’ya aucune raison de stocker des données personnelles sensibles dans vos systèmes. La sécurité est une question complexe, et si vous modifiez votre code tous les jours jusqu'à ce que vous trouviez votre marché digne de ce nom, il se cassera. Supposez que toute personne mal intentionnée pourrait enfreindre votre demande si elle le voulait vraiment.

La clé ici est de ne conserver aucune donnée qui serait une victoire rapide pour un pirate informatique. Personne ne vole une banque qui n'a pas d'argent. Si vous concevez un produit SaaS, vous avez probablement besoin d'une authentification et d'un paiement en ligne. Il y a beaucoup de tiers avec lesquels vous pouvez vous intégrer qui le traiteront d'une bien meilleure façon que vous ne le pourriez probablement.

Auth0, par exemple, est le tiers le plus connu pour gérer l'authentification. Stripe est également une bonne option pour les paiements en ligne. Ils consacreront toutes leurs ressources et les meilleures équipes d'ingénierie de sécurité sur la planète à la protection de vos données - ou ils n'ont pas d'entreprise.

Signe réel sur une voiture à San Francisco

Les services en nuage sont vos meilleurs amis

À ce stade, nous disposions d'un moyen de stocker toutes nos données, notre authentification, notre paiement en ligne et une application Web que les clients pouvaient utiliser, ainsi qu'une API que nous pouvions vendre à nos partenaires pour différents cas d'utilisation. Notre base d'utilisateurs était en pleine croissance et il est devenu évident qu'ils souhaitaient pouvoir accéder à l'application à tout moment. Il était donc temps de penser à l'évolutivité et à la disponibilité.

Nous nous appuyions sur un serveur, mais celui-ci ne pouvait traiter qu'un très grand nombre de demandes. Changer de serveur ou publier une nouvelle version reviendrait à supprimer l'application au cours de la publication. Nos prochaines priorités étaient les suivantes: équilibrage de la charge, mise à l'échelle automatique, journalisation, réplication et sauvegardes automatisées. Bien sûr, si vous êtes le seul ingénieur de votre entreprise, tenter de résoudre tous ces problèmes par vous-même serait une folie absolue.

Heureusement, nous vivons à une époque où un seul ingénieur chevronné peut facilement construire un tel système en quelques jours à l’aide de services Cloud tels que Amazon Web Services, Google Cloud Services ou Azure. Nous avons décidé de transférer nos systèmes vers AWS car à ce moment-là, c'était la solution la plus complète et nous avions deux ans de crédits gratuits.

C'est pourquoi je vais surtout parler des solutions AWS dans cet article, mais il existe des services équivalents sur d'autres plates-formes. C’est également le moment de choisir d’exécuter nos modules dans des conteneurs Docker pour de nombreuses autres raisons qui ne seront pas abordées dans ce message (vous pouvez consulter cet article pour plus d’informations: https://medium.freecodecamp.org / amazon-fargate-au-revoir-infrastructure-3b66c7e3e413).

La manière dont vous décidez d'exécuter vos applications dépend vraiment de votre cas d'utilisation, par exemple de la flexibilité dont vous avez besoin par rapport au temps que vous pouvez consacrer à la gestion de votre infrastructure.

Il n'y a pas de bonne ou de mauvaise réponse.

Vous pouvez choisir de conteneuriser tous vos modules et d'utiliser un système de gestion de conteneurs tel que ECS / EKS dans AWS ou le moteur Kubernetes dans GCP. Si ce n’est pas le cas et que vous ne souhaitez pas gérer vous-même des tâches telles que la mise à l’échelle automatique ou l’équilibrage de la charge, vous pouvez utiliser Elastic Beanstalk ou App Engine.

Si vous voulez aller complet sans serveur, vous pouvez également combiner l'utilisation des fonctions Lambda et de la passerelle API. Nous avons décidé d'aller pour ECS. Nous avons déployé 3 instances dans 3 zones de disponibilité, un équilibreur de charge, configuré la mise à l’échelle automatique en fonction de l’utilisation du processeur, intégré tous les journaux de nos conteneurs à Cloudwatch et configuré des métriques pour surveiller les erreurs, les appels externes et le temps de réponse de l’API.

Haute disponibilité: Saviez-vous que les girafes ne dorment presque jamais? 99% de disponibilité

Pour notre base de données, nous avons utilisé MongoDB, car notre modèle convient parfaitement à une base de données NoSQL et à sa grande cohérence. Nous avons décidé de tirer parti de MongoDB Atlas et avons déployé 3 réplicas pour permettre une haute disponibilité. Parmi les autres services, Atlas fournit des sauvegardes automatiques, à mise à l'échelle automatique, et vous permet de remonter le temps de manière transparente en cas de sinistre.

Nous avons également décidé d'héberger tous nos fichiers Web statiques dans S3 et avons utilisé Cloudfront en tant que CDN afin que nos applications JS puissent se charger très rapidement partout dans le monde et être servies autant de fois que nécessaire. Cloudflare est également une bonne option et offre une protection DDOS prête à l'emploi.

Pour des raisons de simplicité, nous avons décidé d’utiliser Route 53 comme DNS en utilisant leurs serveurs de noms pour tous nos domaines. C'est l'un de mes services préférés sur AWS. Cela rend la vie tellement plus facile. Chaque fois que vous souhaitez servir quelque chose par le biais d'un nom de domaine, qu'il s'agisse d'une instance EC2, d'une IP élastique, d'un équilibreur de charge, d'une distribution Cloudfront ou de quelque chose de vraiment, en privé ou en public, cela vous prend quelques minutes, car il est si bien intégré à tous les autres services.

Combinez cela avec le gestionnaire de certificats qui vous permet d'obtenir des certificats SSL (caractères génériques inclus) gratuitement en quelques minutes et de les déployer sur tous vos serveurs en cochant une case. Vous disposez ainsi du moyen le plus rapide et le plus fiable d'activer HTTPS sur tous vos modules. Adieu les certificats SSL «Let’Encrypt» que je devais renouveler et installer sur mes serveurs tous les 3 mois environ.

Commencer à avoir l'air décent

Choisir une stratégie de cache

Tout le monde déteste la gestion du cache, le cache peut se produire au niveau de nombreuses couches et les problèmes liés au cache sont difficiles à reproduire et le cauchemar à déboguer.

Malheureusement, les performances des systèmes distribués reposent largement sur une bonne stratégie de mise en cache. Il existe de nombreux bons articles sur les bonnes stratégies de mise en cache, aussi je n’entrerai pas dans les détails. Sachez simplement que si vos ressources Web statiques sont lourdes, vous voudrez probablement tirer parti du cache de votre navigateur en utilisant intelligemment l’en-tête de contrôle du cache.

Si les pages en regard de votre utilisateur sont générées sur les serveurs d’applications, utilisez un proxy de mise en cache tel que Squid. Mais surtout, il y a de fortes chances que vous fassiez encore et encore les mêmes requêtes à votre base de données. Pour réduire la charge de votre base de données et économiser sur le temps de transfert des données, utilisez un système de mise en cache des objets mémoire tel que memcached pour les objets fréquemment utilisés et rarement mis à jour.

Nous avons commencé à envisager d'utiliser memcached parce que nous demandions souvent les mêmes profils de candidats et offres d'emploi, encore et encore. Son implémentation sur une machine optimisée pour la mémoire a augmenté les performances de notre API de plus de 30% lorsque nous calculons la moyenne des temps de réponse des demandes par jour. Memcached est également distribué. Il peut donc s’exécuter sur différents serveurs, tout en agissant comme s’il ne s’agissait que d’un seul grand espace mémoire pour stocker vos objets.

cache, cache partout

Emplacement, emplacement, emplacement

Nous avons maintenant un système distribué qui n’a pas un seul point de défaillance (si vous considérez les AWB ELB et un memcached distribué), et qui peut être automatiquement mis à l’échelle. Nous utilisons également la mise en cache pour minimiser les transferts de données sur le réseau. Ça a l'air bien. À ce stade, vous souhaiterez probablement auditer vos tierces parties pour voir si elles absorberont la charge aussi bien que vous.

Cependant, certains de nos utilisateurs se plaignaient du fait que l'application leur était un peu plus lente, en particulier lorsqu'ils téléchargeaient des fichiers. En effet, même si nos fichiers Web statiques étaient mis en cache dans le monde entier (avec la permission du CDN), tous nos serveurs d’application n’étaient déployés que dans l’ouest des États-Unis. Les utilisateurs de l'Asie de l'Est ont connu beaucoup plus de latence, en particulier pour les transferts Big Data.

La solution était simple: déployer exactement le même cluster ECS dans une nouvelle région en Asie avec un nouvel équilibreur de charge et utiliser le routage de la géoproximité Route 53 pour acheminer les utilisateurs vers l'équilibreur de charge le plus proche. MongoDB Atlas vous permet également de déployer vos répliques dans toutes les régions de sorte qu'aucun travail supplémentaire ne soit nécessaire.

Et nous voici ! Notre système distribué est prêt.

Conclusion

Alors que le système distribué que vous voyez ici a été simplifié pour ce billet, nous avons examiné les éléments que vous êtes le plus susceptible de voir dans de nombreuses applications Web modernes. Les autres sujets liés à, mais non couverts, sont l’architecture des microservices, le stockage et le cryptage de fichiers, le partage de bases de données, les tâches planifiées, l’informatique parallèle asynchrone… peut-être dans le prochain article!

Mon point principal est le suivant: n’essayez pas de créer le système parfait lorsque vous démarrez votre produit. La plupart de vos choix de conception dépendront de ce que votre produit fait et de qui l’utilise. Vous saurez seulement que lorsque vous atteignez le marché, vous commencez à avoir une bonne vue d'ensemble de votre clientèle, ce qui peut prendre des mois, voire des années.

Concentrez-vous sur ce dont les gens ont besoin et essayez de trouver une solution à leur problème, même s'il comporte de nombreuses étapes manuelles. Ensuite, réfléchissez aux moyens d’automatiser, passez votre temps à coder et à détruire, et faites appel à des tiers lorsque cela se justifie.

Ne pas mettre à l’échelle, mais toujours penser, coder et planifier la mise à l’échelle. Construisez votre système étape par étape, ne résolvez pas les problèmes de conception du système en vous basant sur des fonctionnalités qui ne sont pas encore matures et, finalement, essayez toujours de trouver le meilleur compromis possible entre le temps que vous allez dépenser et le gain de performance, d'argent et de réduction risque.

Si vous avez aimé cet article et que vous en avez trouvé une utile, appuyez sur le bouton Clap et suivez-moi pour en savoir plus sur l'architecture et le développement!