De nombreuses startups ont vécu cela : des foules de nouveaux utilisateurs s'inscrivent chaque jour et l'équipe de développement a du mal à faire fonctionner le service.
C'est un problÚme intéressant, mais il existe peu d'informations claires sur le Web sur la façon de faire évoluer soigneusement une application Web de rien à des centaines de milliers d'utilisateurs. Il existe généralement soit des solutions anti-incendie, soit des solutions aux goulots d'étranglement (et souvent les deux). Par conséquent, les gens utilisent des techniques plutÎt clichées pour transformer leur projet amateur en quelque chose de vraiment sérieux.
Essayons de filtrer les informations et d'écrire la formule de base. Nous allons faire évoluer notre nouveau site de partage de photos Graminsta étape par étape de 1 à 100 000 utilisateurs.
Ăcrivons quelles actions spĂ©cifiques doivent ĂȘtre entreprises lorsque l'audience passe Ă 10, 100, 1000 10, 000 100 et 000 XNUMX personnes.
1 utilisateur : 1 machine
Presque toutes les applications, qu'il s'agisse d'un site Web ou d'une application mobile, comportent trois éléments clés :
- API
- base de données
- client (application mobile elle-mĂȘme ou site Web)
La base de donnĂ©es stocke les donnĂ©es persistantes. L'API rĂ©pond aux requĂȘtes vers et autour de ces donnĂ©es. Le client transmet des donnĂ©es Ă l'utilisateur.
Je suis arrivé à la conclusion qu'il est beaucoup plus facile de parler de mise à l'échelle d'une application si, d'un point de vue architectural, les entités client et API sont complÚtement séparées.
Lorsque nous commençons Ă crĂ©er une application, les trois composants peuvent ĂȘtre exĂ©cutĂ©s sur le mĂȘme serveur. D'une certaine maniĂšre, cela ressemble Ă notre environnement de dĂ©veloppement : un ingĂ©nieur exĂ©cute la base de donnĂ©es, l'API et le client sur la mĂȘme machine.
En théorie, nous pourrions le déployer dans le cloud sur une seule instance DigitalOcean Droplet ou AWS EC2, comme indiqué ci-dessous :

Cela dit, sâil y a plus dâun utilisateur sur un site, il est presque toujours logique de dĂ©dier une couche de base de donnĂ©es.
10 utilisateurs : déplacer la base de données vers un niveau distinct
Diviser la base de donnĂ©es en services gĂ©rĂ©s comme Amazon RDS ou Digital Ocean Managed Database nous servira pendant longtemps. C'est un peu plus cher que l'auto-hĂ©bergement sur une seule machine ou une instance EC2, mais avec ces services, vous obtenez de nombreuses extensions utiles prĂȘtes Ă l'emploi qui vous seront utiles Ă l'avenir : sauvegarde multi-rĂ©gions, rĂ©plicas en lecture, sauvegarde automatique. sauvegardes, et plus encore.
Voici Ă quoi ressemble le systĂšme maintenant :

100 utilisateurs : déplacer le client vers un niveau distinct
Heureusement, nos premiers utilisateurs ont beaucoup aimĂ© notre application. Le trafic devient plus stable, il est donc temps de dĂ©placer le client vers un niveau distinct. Il convient de noter que sĂ©paration Les entitĂ©s sont un aspect clĂ© de la crĂ©ation dâune application Ă©volutive. Lorsqu'une partie du systĂšme reçoit davantage de trafic, nous pouvons la partitionner pour contrĂŽler la façon dont le service Ă©volue en fonction de modĂšles de trafic spĂ©cifiques.
Câest pourquoi jâaime considĂ©rer le client sĂ©parĂ©ment de lâAPI. Cela facilite grandement le dĂ©veloppement pour plusieurs plateformes : web, web mobile, iOS, etc. AndroidApplications de bureau, services tiers, etc. Ce sont tous des clients utilisant la mĂȘme API.
Par exemple, nos utilisateurs demandent désormais le plus souvent de publier une application mobile. Si vous séparez les entités client et API, cela devient plus facile.
Voici Ă quoi ressemble un tel systĂšme :

1000 utilisateurs : ajouter un équilibreur de charge
Les choses s'améliorent. Les utilisateurs de Graminsta téléchargent de plus en plus de photos. Le nombre d'inscriptions est également en augmentation. Notre seul serveur API a du mal à suivre tout le trafic. Il me faut plus de fer !
L'Ă©quilibreur de charge est un concept trĂšs puissant. L'idĂ©e clĂ© est que nous plaçons un Ă©quilibreur de charge devant l'API et qu'il distribue le trafic aux instances de service individuelles. C'est ainsi que nous Ă©voluons horizontalement, ce qui signifie que nous ajoutons plus de serveurs avec le mĂȘme code, augmentant ainsi le nombre de requĂȘtes que nous pouvons traiter.
Nous allons placer des Ă©quilibreurs de charge distincts devant le client web et devant l'API. Cela signifie que vous pouvez exĂ©cuter plusieurs instances exĂ©cutant le code API et le code client Web. L'Ă©quilibreur de charge dirigera les requĂȘtes vers le serveur le moins chargĂ©.
Ici, nous obtenons un autre avantage important : la redondance. Lorsqu'une instance Ă©choue (peut-ĂȘtre surchargĂ©e ou en panne), nous nous retrouvons avec d'autres qui continuent de rĂ©pondre aux demandes entrantes. Sâil nây avait quâune seule instance qui fonctionnait, en cas de panne, tout le systĂšme tomberait en panne.
L'équilibreur de charge fournit également une mise à l'échelle automatique. Nous pouvons le configurer pour augmenter le nombre d'instances avant la charge maximale et le diminuer lorsque tous les utilisateurs dorment.
Avec un Ă©quilibreur de charge, le niveau de l'API peut ĂȘtre adaptĂ© presque indĂ©finiment, en ajoutant simplement de nouvelles instances Ă mesure que le nombre de requĂȘtes augmente.

Note. Ă l'heure actuelle, notre systĂšme est trĂšs similaire Ă ce que proposent des sociĂ©tĂ©s PaaS comme Heroku ou Elastic Beanstalk sur AWS (c'est pourquoi elles sont si populaires). Heroku place la base de donnĂ©es sur un hĂŽte distinct, gĂšre un Ă©quilibreur de charge Ă mise Ă l'Ă©chelle automatique et vous permet d'hĂ©berger le client Web sĂ©parĂ©ment de l'API. C'est une excellente raison d'utiliser Heroku pour des projets en phase de dĂ©marrage ou des startups : vous obtenez tous les services de base prĂȘts Ă l'emploi.
10 000 utilisateurs : CDN
Peut-ĂȘtre aurions-nous dĂ» le faire dĂšs le dĂ©but. Le traitement des demandes et l'acceptation de nouvelles photos commencent Ă mettre trop de pression sur nos serveurs.
à ce stade, vous devez utiliser un service cloud pour stocker du contenu statique - images, vidéos et bien plus encore (AWS S3 ou Digital Ocean Spaces). En général, notre API devrait éviter de gérer des choses comme la diffusion d'images et le téléchargement d'images sur le serveur.
Un autre avantage de l'hébergement cloud est le CDN (AWS appelle ce module complémentaire Cloudfront, mais de nombreux fournisseurs de stockage cloud le proposent directement). Le CDN met automatiquement en cache nos images dans divers centres de données à travers le monde.
Bien que notre centre de données principal soit situé dans l'Ohio, si quelqu'un demande une image au Japon, le fournisseur de cloud en fera une copie et la stockera dans son centre de données japonais. La prochaine personne qui demandera cette image au Japon la recevra beaucoup plus rapidement. Ceci est important lorsque nous travaillons avec des fichiers volumineux, comme des photos ou des vidéos, qui prennent beaucoup de temps à télécharger et à transmettre à travers la planÚte.

100 000 utilisateurs : faire évoluer la couche de données
CDN a beaucoup aidĂ© : le trafic croĂźt Ă toute vitesse. Le cĂ©lĂšbre blogueur vidĂ©o Mavid Mobrick vient de s'inscrire chez nous et de publier son « histoire », comme on dit. GrĂące Ă l'Ă©quilibreur de charge, l'utilisation du CPU et de la mĂ©moire sur les serveurs API reste faible (dix instances API en cours d'exĂ©cution), mais nous commençons Ă avoir beaucoup de timeouts sur les requĂȘtes... d'oĂč viennent ces retards ?
En creusant un peu dans les métriques, nous constatons que le processeur du serveur de base de données est chargé à 80-90 %. Nous sommes à la limite.
La mise Ă lâĂ©chelle de la couche de donnĂ©es est probablement la partie la plus difficile de lâĂ©quation. Les serveurs API traitent les requĂȘtes sans Ă©tat, nous ajoutons donc simplement plus d'instances API. Nez Ă la majoritĂ© les bases de donnĂ©es ne peuvent pas faire cela. Nous parlerons des systĂšmes de gestion de bases de donnĂ©es relationnelles populaires (PostgreSQL, MySQL, etc.).
mise en cache
L'un des moyens les plus simples d'augmenter les performances de notre base de données est d'introduire un nouveau composant : la couche de cache. La méthode de mise en cache la plus courante est un magasin d'enregistrements clé-valeur en mémoire, tel que Redis ou Memcached. La plupart des cloud disposent d'une version gérée de ces services : Elasticache sur AWS et Memorystore sur Google Cloud.
Un cache est utile lorsqu'un service effectue de nombreux appels rĂ©pĂ©tĂ©s Ă la base de donnĂ©es pour rĂ©cupĂ©rer les mĂȘmes informations. Essentiellement, nous accĂ©dons Ă la base de donnĂ©es une seule fois, stockons les informations dans le cache et n'y touchons plus.
Par exemple, dans notre service Graminsta, chaque fois que quelqu'un accĂšde Ă la page de profil de la star Mobrik, le serveur API interroge la base de donnĂ©es pour obtenir des informations sur son profil. Cela arrive encore et encore. Ătant donnĂ© que les informations de profil de Mobrik ne changent pas Ă chaque demande, elles sont excellentes pour la mise en cache.
Nous mettrons en cache les résultats de la base de données dans Redis par clé user:id avec une durée de validité de 30 secondes. Désormais, lorsque quelqu'un accÚde au profil de Mobrik, nous vérifions d'abord Redis, et si les données sont là , nous les transférons simplement directement depuis Redis. Désormais, les demandes adressées au profil le plus populaire du site ne chargent pratiquement pas notre base de données.
Un autre avantage de la plupart des services de mise en cache est quâils sont plus faciles Ă mettre Ă lâĂ©chelle que les serveurs de bases de donnĂ©es. Redis dispose d'un mode Redis Cluster intĂ©grĂ©. Semblable Ă un Ă©quilibreur de charge, il vous permet de distribuer votre cache Redis sur plusieurs machines (sur des milliers de serveurs si nĂ©cessaire).
Presque toutes les applications Ă grande Ă©chelle utilisent la mise en cache ; elle fait absolument partie intĂ©grante d'une API rapide. Un traitement des requĂȘtes plus rapide et un code plus productif sont tous importants, mais sans cache, il est presque impossible de faire Ă©voluer un service vers des millions d'utilisateurs.
Lire les répliques
Lorsque le nombre de requĂȘtes sur la base de donnĂ©es a considĂ©rablement augmentĂ©, une autre chose que nous pouvons faire est d'ajouter des rĂ©plicas en lecture dans le systĂšme de gestion de base de donnĂ©es. Avec les services gĂ©rĂ©s dĂ©crits ci-dessus, cela peut se faire en un clic. Le rĂ©plica en lecture restera Ă jour dans la base de donnĂ©es principale et est disponible pour les instructions SELECT.
Voici notre systĂšme maintenant :

Prochaines étapes
Ă mesure que lâapplication continue dâĂ©voluer, nous continuerons Ă sĂ©parer les services pour les faire Ă©voluer indĂ©pendamment. Par exemple, si nous commençons Ă utiliser Websockets, il est alors logique d'extraire le code de traitement des Websockets dans un service distinct. Nous pouvons le placer sur de nouvelles instances derriĂšre notre propre Ă©quilibreur de charge, qui peut Ă©voluer en fonction des connexions Websockets ouvertes et quel que soit le nombre de requĂȘtes HTTP.
Nous continuerons Ă©galement Ă lutter contre les restrictions au niveau des bases de donnĂ©es. Câest Ă ce stade quâil est temps dâĂ©tudier le partitionnement et le partitionnement des bases de donnĂ©es. Les deux approches nĂ©cessitent une surcharge supplĂ©mentaire, mais vous permettent de faire Ă©voluer la base de donnĂ©es presque indĂ©finiment.
Nous souhaitons Ă©galement installer un service de surveillance et d'analyse comme New Relic ou Datadog. Cela vous aidera Ă identifier les requĂȘtes lentes et Ă comprendre oĂč des amĂ©liorations sont nĂ©cessaires. Ă mesure que nous progressons, nous souhaitons nous concentrer sur la recherche des goulots dâĂ©tranglement et sur leur Ă©limination, en utilisant souvent certaines des idĂ©es des sections prĂ©cĂ©dentes.
sources
Cet article est inspiré par l'un des . Je voulais rendre l'article un peu plus spécifique pour les étapes initiales des projets et le détacher d'un seul fournisseur. Assurez-vous de lire si ce sujet vous intéresse.
Notes de bas de page
- Bien que similaire en termes de répartition de charge sur plusieurs instances, l'implémentation sous-jacente d'un cluster Redis est trÚs différente de celle d'un équilibreur de charge.
Source: habr.com
