Salut, Habr !
à la lumiÚre des événements actuels liés au coronavirus, plusieurs services en ligne font face à une charge accrue. Par exemple, car les ressources n'étaient pas suffisantes. De plus, il n'est pas toujours possible d'accélérer un serveur simplement en ajoutant du matériel plus puissant, mais il est nécessaire de traiter les demandes des clients (sinon, ils iront chez les concurrents).
Dans cet article, je vais briĂšvement parler des pratiques populaires qui permettront de crĂ©er un service rapide et rĂ©silient. Cependant, parmi les schĂ©mas de dĂ©veloppement possibles, j'ai sĂ©lectionnĂ© uniquement ceux que vous pouvez actuellement facilement utiliser.Pour chaque point, vous avez soit dĂ©jĂ des bibliothĂšques prĂȘtes Ă l'emploi, soit la possibilitĂ© de rĂ©soudre le problĂšme en utilisant une plateforme cloud.
Scalabilité horizontale
Le point le plus simple et le plus connu. On distingue généralement deux méthodes de répartition de la charge : la scalabilité horizontale et verticale. vous permettez aux services de fonctionner en parallÚle, répartissant ainsi la charge entre eux. vous commandez des serveurs plus puissants ou optimisez le code.
à titre d'exemple, je vais prendre un stockage cloud abstrait de fichiers, c'est-à -dire un certain équivalent d'OwnCloud, OneDrive, etc.
L'image standard de ce type de schéma est ci-dessous, mais elle ne fait qu'illustrer la complexité du systÚme. En effet, nous devons synchroniser les services. Que se passe-t-il si un utilisateur sauvegarde un fichier depuis sa tablette et souhaite ensuite le consulter sur son téléphone ?

La diffĂ©rence entre les approches : dans la scalabilitĂ© verticale, nous sommes prĂȘts Ă accroĂźtre la puissance des nĆuds, tandis que dans la scalabilitĂ© horizontale, nous ajoutons de nouveaux nĆuds pour rĂ©partir la charge.
CQRS
est un modĂšle assez important, car il permet Ă diffĂ©rents clients non seulement de se connecter Ă diffĂ©rents services, mais Ă©galement de recevoir des flux d'Ă©vĂ©nements identiques. Ses avantages ne sont pas si Ă©vidents pour une application simple, mais ils sont extrĂȘmement importants (et simples) pour un service chargĂ©. Son principe : les flux de donnĂ©es entrants et sortants ne doivent pas se croiser. En d'autres termes, vous ne pouvez pas envoyer une requĂȘte et attendre une rĂ©ponse, au lieu de cela, vous envoyez une requĂȘte au service A, mais vous obtenez une rĂ©ponse dans le service B.
Le premier avantage de cette approche est la possibilitĂ© d'interrompre la connexion (au sens large du terme) pendant l'exĂ©cution d'une longue requĂȘte. Prenons par exemple une sĂ©quence standard :
- Le client a envoyĂ© une requĂȘte au serveur.
- Le serveur a lancé un traitement long.
- Le serveur a répondu au client avec un résultat.
Imaginons que, dans le point 2, une interruption de connexion se soit produite (soit en raison d'une déconnexion réseau, soit parce que l'utilisateur est passé à une autre page, rompant ainsi la connexion). Dans ce cas, il sera difficile pour le serveur d'envoyer une réponse à l'utilisateur concernant ce qui a été traité. En appliquant CQRS, la séquence sera légÚrement différente :
- Le client s'est abonné aux mises à jour.
- Le client a envoyĂ© une requĂȘte au serveur.
- Le serveur a rĂ©pondu « requĂȘte reçue ».
- Le serveur a répondu avec le résultat via le canal du point « 1 ».

Comme on le voit, le schĂ©ma est lĂ©gĂšrement plus complexe. De plus, l'approche intuitive request-response est absente ici. Cependant, comme on peut le voir, une interruption de connexion pendant le traitement de la requĂȘte ne conduira pas Ă une erreur. De plus, si l'utilisateur est effectivement connectĂ© au service depuis plusieurs appareils (par exemple, un tĂ©lĂ©phone mobile et une tablette), il est possible de faire en sorte que la rĂ©ponse parvienne aux deux appareils.
Il est intĂ©ressant de noter que le code de traitement des messages entrants devient identique (Ă 100 %) tant pour les Ă©vĂ©nements affectĂ©s par le client lui-mĂȘme que pour les autres Ă©vĂ©nements, y compris ceux d'autres clients.
Cependant, dans la rĂ©alitĂ©, nous obtenons des avantages supplĂ©mentaires grĂące au fait qu'un flux unidirectionnel peut ĂȘtre traitĂ© de maniĂšre fonctionnelle (en utilisant RX et des analogues). Et c'est dĂ©jĂ un vrai plus, car en substance, l'application peut devenir complĂštement rĂ©active, tout en utilisant Ă©galement une approche fonctionnelle. Pour les applications lourdes, cela peut considĂ©rablement Ă©conomiser des ressources en dĂ©veloppement et en maintenance.
Si nous combinons cette approche avec une mise Ă l'Ă©chelle horizontale, alors nous obtenons en prime la possibilitĂ© d'envoyer des requĂȘtes Ă un serveur tout en recevant des rĂ©ponses d'un autre. Ainsi, le client peut choisir le service qui lui convient le mieux, et le systĂšme Ă l'intĂ©rieur pourra tout de mĂȘme traiter les Ă©vĂ©nements de maniĂšre appropriĂ©e.
Event Sourcing
Comme vous le savez, l'une des caractĂ©ristiques principales d'un systĂšme distribuĂ© est l'absence de temps commun et de section critique partagĂ©e. Pour un seul processus, vous pouvez effectuer une synchronisation (sur les mĂȘmes mutex), oĂč vous ĂȘtes sĂ»r que personne d'autre n'exĂ©cute ce code. Cependant, pour un systĂšme distribuĂ©, cela peut ĂȘtre dangereux, car cela entraĂźnera des frais gĂ©nĂ©raux et ruinera tout l'intĂ©rĂȘt de l'Ă©volutivitĂ© : tous les composants devront attendre les uns les autres.
D'ici, nous obtenons un fait important : un systĂšme distribuĂ© rapide ne peut pas ĂȘtre synchronisĂ©, car cela diminuerait les performances. D'un autre cĂŽtĂ©, nous avons souvent besoin d'une certaine cohĂ©rence des composants. Et pour cela, nous pouvons utiliser l'approche de , qui garantit qu'en l'absence de modifications des donnĂ©es, aprĂšs un certain laps de temps aprĂšs la derniĂšre mise Ă jour (« en fin de compte »), toutes les requĂȘtes renverront la derniĂšre valeur mise Ă jour.
Il est important de comprendre qu'une est souvent appliquĂ©e aux bases de donnĂ©es classiques, oĂč chaque nĆud possĂšde les mĂȘmes informations (ce qui est souvent rĂ©alisĂ© lorsqu'une transaction est considĂ©rĂ©e comme Ă©tablie uniquement aprĂšs la rĂ©ponse d'un deuxiĂšme serveur). Il existe certaines concessions dues aux niveaux d'isolation, mais l'idĂ©e principale reste la mĂȘme : vous pouvez vivre dans un monde complĂštement cohĂ©rent.
Cependant, revenons Ă la tĂąche initiale. Si une partie du systĂšme peut ĂȘtre construite avec , alors on peut construire le schĂ©ma suivant.

Caractéristiques importantes de cette approche :
- Chaque requĂȘte entrante est placĂ©e dans une seule file d'attente.
- Au cours du traitement de la requĂȘte, le service peut Ă©galement placer des tĂąches dans d'autres files d'attente.
- Chaque événement entrant a un identifiant (nécessaire pour la déduplication).
- La file d'attente fonctionne idéologiquement selon le principe "ajout uniquement". On ne peut pas supprimer des éléments ou les réorganiser.
- La file d'attente fonctionne selon le schéma FIFO (désolé pour la tautologie). Si une exécution parallÚle est nécessaire, il conviendrait à un des niveaux de redistribuer les objets dans différentes files d'attente.
Je rappelle que nous examinons le cas d'un stockage de fichiers en ligne. Dans ce cas, le systĂšme ressemblera, environ, Ă ceci :

Il est important de noter que les services sur le diagramme ne signifient pas nĂ©cessairement un serveur sĂ©parĂ©. Le processus peut ĂȘtre identique. Ce qui est crucial, c'est que ces Ă©lĂ©ments sont idĂ©ologiquement sĂ©parĂ©s de maniĂšre Ă faciliter l'application de l'Ă©volutivitĂ© horizontale.
Pour deux utilisateurs, le schéma apparaßtra comme suit (les services destinés à différents utilisateurs sont indiqués en différentes couleurs) :

Les avantages d'une telle combinaison :
- Les services de traitement de données sont séparés. Les files d'attente sont également distinctes. Si nous devons augmenter la capacité de la systÚme, il suffit de lancer davantage de services sur un plus grand nombre de serveurs.
- Lorsque nous recevons des informations de l'utilisateur, nous ne devons pas nécessairement attendre la sauvegarde complÚte des données. Au contraire, il est suffisant de répondre « ok », puis de commencer progressivement à travailler. De plus, la file d'attente atténue les pics, car l'ajout d'un nouvel objet se fait rapidement, et l'utilisateur n'a pas à attendre un passage complet par tout le cycle.
- à titre d'exemple, j'ai ajouté un service de déduplication qui tente de regrouper les fichiers identiques. S'il fonctionne longuement dans 1% des cas, le client ne le remarquera pratiquement pas (voir ci-dessus), ce qui est un grand avantage, car nous ne demandons plus une vitesse et une fiabilité à 100%.
Cependant, les inconvénients sont également évidents :
- Notre systĂšme a perdu une cohĂ©rence stricte. Cela signifie que si, par exemple, on s'abonne Ă diffĂ©rents services, il est thĂ©oriquement possible d'obtenir des Ă©tats diffĂ©rents (puisqu'un des services peut ne pas rĂ©ussir Ă recevoir la notification de la file d'attente interne). Comme autre consĂ©quence, le systĂšme n'a plus de temps commun. Autrement dit, il n'est pas possible, par exemple, de trier tous les Ă©vĂ©nements simplement par ordre d'arrivĂ©e, car les horloges entre les serveurs peuvent ne pas ĂȘtre synchronisĂ©es (de plus, deux serveurs ayant la mĂȘme heure est une utopie).
- Aucun Ă©vĂ©nement ne peut maintenant ĂȘtre simplement annulĂ© (comme cela aurait pu ĂȘtre fait avec une base de donnĂ©es). Au lieu de cela, il est nĂ©cessaire d'ajouter un nouvel Ă©vĂ©nement â , qui va changer le dernier Ă©tat en celui requis. Un exemple d'un domaine similaire : sans réécriture de l'historique (ce qui est mauvais dans certains cas), il n'est pas possible de revenir Ă un commit dans git, mais on peut faire un spĂ©cial , qui en fait ne renverra qu'Ă l'Ă©tat prĂ©cĂ©dent. Cependant, l'historique conservera Ă la fois le commit erronĂ© et le rollback.
- Le schĂ©ma des donnĂ©es peut changer d'une version Ă l'autre, cependant, il ne sera plus possible de mettre Ă jour les anciens Ă©vĂ©nements vers le nouveau standard (car les Ă©vĂ©nements ne peuvent en principe pas ĂȘtre modifiĂ©s).
Comme on peut le voir, l'Event Sourcing s'intĂšgre parfaitement avec le CQRS. De plus, mettre en place un systĂšme avec des files d'attente efficaces et pratiques, mais sans sĂ©paration des flux de donnĂ©es, est dĂ©jĂ en soi compliquĂ©, car il faudra ajouter des points de synchronisation qui annuleront tout l'effet positif des files d'attente. En appliquant les deux approches simultanĂ©ment, il est nĂ©cessaire d'ajuster lĂ©gĂšrement le code de l'application. Dans notre cas, lors de l'envoi d'un fichier au serveur, la rĂ©ponse ne contient que « ok », ce qui signifie simplement que « l'opĂ©ration d'ajout de fichier a Ă©tĂ© enregistrĂ©e ». Formellement, cela n'indique pas que les donnĂ©es sont dĂ©jĂ accessibles sur d'autres appareils (par exemple, un service de dĂ©-duplication peut ĂȘtre en train de reconstruire l'index). Cependant, aprĂšs un certain temps, le client recevra une notification du type « fichier X enregistrĂ© ».
En conséquence :
- Le nombre de statuts d'envoi de fichiers augmente : au lieu du classique « fichier envoyé », nous obtenons deux : « fichier ajouté à la file d'attente sur le serveur » et « fichier enregistré dans le stockage ». Ce dernier signifie que d'autres appareils peuvent déjà commencer à recevoir le fichier (avec la nuance que les files d'attente fonctionnent à des vitesses différentes).
- En raison du fait que l'information sur l'envoi arrive maintenant par diffĂ©rents canaux, nous devons trouver des solutions pour obtenir le statut de traitement du fichier. En consĂ©quence, contrairement Ă la mĂ©thode classique de requĂȘte-rĂ©ponse, le client peut ĂȘtre redĂ©marrĂ© pendant le traitement du fichier, mais le statut de ce traitement sera correct. De plus, ce point fonctionne en fait de maniĂšre native. En consĂ©quence : nous sommes maintenant plus tolĂ©rants aux pannes.
Sharding
Comme déjà mentionné, dans les systÚmes avec event sourcing, il n'y a pas de cohérence stricte. Cela signifie que nous pouvons utiliser plusieurs stockages sans aucune synchronisation entre eux. En nous rapprochant de notre tùche, nous pouvons :
- SĂ©parer les fichiers par types. Par exemple, les images/vidĂ©os peuvent ĂȘtre dĂ©codĂ©es et choisies dans un format plus efficace.
- SĂ©parer les comptes par pays. En raison de nombreuses lois, cela peut ĂȘtre nĂ©cessaire, cependant, cette architecture offre une telle possibilitĂ© automatiquement.

Si vous souhaitez transfĂ©rer des donnĂ©es d'un stockage Ă un autre, les moyens standards ne suffisent pas ici. Malheureusement, dans ce cas, il est nĂ©cessaire d'arrĂȘter la file d'attente, de faire la migration, puis de la relancer. En gĂ©nĂ©ral, les donnĂ©es ne peuvent pas ĂȘtre transfĂ©rĂ©es 'Ă la volĂ©e', cependant, si la file d'Ă©vĂ©nements est entiĂšrement conservĂ©e, et que vous avez des instantanĂ©s des Ă©tats prĂ©cĂ©dents du stockage, nous pouvons rejouer les Ă©vĂ©nements comme suit :
- Dans Event Source, chaque Ă©vĂ©nement a son identifiant (idĂ©alement â non dĂ©croissant). Cela signifie que nous pouvons ajouter un champ dans le stockage â id du dernier Ă©lĂ©ment traitĂ©.
- Nous dupliquons la file d'attente, afin que tous les Ă©vĂ©nements puissent ĂȘtre traitĂ©s pour plusieurs stockages indĂ©pendants (le premier Ă©tant celui oĂč les donnĂ©es sont dĂ©jĂ stockĂ©es, et le second Ă©tant nouveau, mais encore vide). La seconde file d'attente n'est bien sĂ»r pas encore traitĂ©e.
- Nous lançons la seconde file d'attente (c'est-à -dire que nous commençons à rejouer les événements).
- Lorsque la nouvelle file d'attente sera relativement vide (c'est-à -dire que l'écart moyen de temps entre l'ajout d'un élément et sa récupération sera acceptable), nous pourrons commencer à rediriger les lecteurs vers le nouveau stockage.
Comme on peut le voir, notre systĂšme n'a jamais eu de cohĂ©rence stricte. Il y a seulement une constance Ă©ventuelle, c'est-Ă -dire la garantie que les Ă©vĂ©nements sont traitĂ©s dans le mĂȘme ordre (mais, peut-ĂȘtre, avec un dĂ©calage diffĂ©rent). En profitant de cela, nous pouvons relativement facilement transfĂ©rer des donnĂ©es sans arrĂȘter le systĂšme Ă l'autre bout du monde.
Ainsi, en continuant notre exemple d'un stockage en ligne pour fichiers, une telle architecture nous offre déjà plusieurs avantages :
- Nous pouvons déplacer des objets plus prÚs des utilisateurs, de maniÚre dynamique. Cela peut ainsi améliorer la qualité du service.
- Nous pouvons stocker une partie des données à l'intérieur des entreprises. Par exemple, les utilisateurs d'entreprise exigent souvent que leurs données soient stockées dans des centres de données sous contrÎle (pour éviter les fuites de données). Grùce au sharding, nous pouvons facilement soutenir cela. Et la tùche est encore simplifiée si le client a un cloud compatible (par exemple, ).
- Le plus important est que nous n'avons pas Ă le faire. En fait, au dĂ©part, un seul stockage pour tous les comptes nous suffirait (pour commencer Ă travailler plus rapidement). La caractĂ©ristique clĂ© de ce systĂšme est qu'il est simple au dĂ©part, bien qu'il soit extensible. Il suffit de ne pas Ă©crire immĂ©diatement le code qui traite un million de files d'attente indĂ©pendantes, etc. Si nĂ©cessaire, cela peut ĂȘtre fait Ă l'avenir.
Hébergement de Contenu Statique
Ce point peut sembler Ă©vident, mais il est nĂ©anmoins nĂ©cessaire pour une application chargĂ©e relativement standard. Son essence est simple : tout le contenu statique est distribuĂ© non pas depuis le mĂȘme serveur que l'application, mais depuis des serveurs dĂ©diĂ©s Ă cet effet. En consĂ©quence, ces opĂ©rations sont effectuĂ©es plus rapidement (un nginx par exemple, distribue les fichiers de maniĂšre plus efficace et moins coĂ»teuse qu'un serveur Java). De plus, l'architecture CDN () permet de placer nos fichiers plus prĂšs des utilisateurs finaux, ce qui amĂ©liore l'ergonomie de l'utilisation du service.
Le meilleur exemple de contenu statique est un ensemble de scripts et d'images pour un site web. C'est assez simple - ils sont connus Ă l'avance, puis l'archive est tĂ©lĂ©chargĂ©e sur les serveurs CDN, d'oĂč elle est distribuĂ©e aux utilisateurs finaux.
Cependant, en rĂ©alitĂ©, pour le contenu statique, nous pouvons appliquer une approche similaire Ă l'architecture lambda. Revenons Ă notre tĂąche (un stockage de fichiers en ligne), oĂč nous devons distribuer des fichiers aux utilisateurs. La solution la plus simple serait de crĂ©er un service qui effectue toutes les vĂ©rifications nĂ©cessaires (authentification, etc.) pour chaque demande utilisateur, puis tĂ©lĂ©charge le fichier directement depuis notre stockage. Le principal inconvĂ©nient de cette approche est que le contenu statique (et un fichier avec un certain rĂ©vision est essentiellement du contenu statique) est distribuĂ© par le mĂȘme serveur qui contient la logique mĂ©tier. Au lieu de cela, nous pouvons proposer le schĂ©ma suivant :
- Le serveur fournit une URL de tĂ©lĂ©chargement. Elle peut ĂȘtre sous la forme file_id + key, oĂč la key est une signature numĂ©rique courte, donnant accĂšs Ă la ressource pour les prochaines 24 heures.
- La distribution du fichier est gérée par un simple nginx avec les options suivantes :
- Mise en cache du contenu. Ătant donnĂ© que ce service peut ĂȘtre sur un serveur sĂ©parĂ©, nous nous sommes laissĂ©s une marge pour l'avenir avec la possibilitĂ© de stocker tous les fichiers tĂ©lĂ©chargĂ©s rĂ©cemment sur le disque.
- Vérification de la clé au moment de la création de la connexion
- En option : traitement en continu du contenu. Par exemple, si nous compressons tous les fichiers dans le service, il est possible de dĂ©compresser directement dans ce module. Par consĂ©quent, les opĂ©rations IO sont effectuĂ©es lĂ oĂč elles ont le plus de sens. Un archiveur en Java pourrait facilement consommer beaucoup de mĂ©moire, mais réécrire le service avec la logique mĂ©tier en Rust/C++ pourrait Ă©galement s'avĂ©rer inefficace. Dans notre cas, diffĂ©rents processus (ou mĂȘme services) sont utilisĂ©s, ce qui permet de sĂ©parer efficacement la logique mĂ©tier des opĂ©rations IO.

Un tel schĂ©ma ressemble peu Ă la distribution de contenu statique (car nous ne tĂ©lĂ©chargeons pas l'ensemble du paquet statique quelque part), mais dans la rĂ©alitĂ©, cette approche s'occupe bien de la distribution de donnĂ©es immuables. De plus, ce schĂ©ma peut ĂȘtre gĂ©nĂ©ralisĂ© Ă d'autres cas, oĂč le contenu n'est pas simplement statique, mais peut ĂȘtre reprĂ©sentĂ© par un ensemble de blocs immuables et non supprimables (bien qu'ils puissent ĂȘtre ajoutĂ©s).
Un autre exemple (pour bien illustrer) : si vous avez travaillĂ© avec Jenkins/TeamCity, vous savez que les deux solutions sont Ă©crites en Java. Elles reprĂ©sentent toutes deux un processus Java qui s'occupe Ă la fois de l'orchestration des builds et de la gestion du contenu. En particulier, elles ont toutes deux des tĂąches du type "transfĂ©rer un fichier/dossier depuis le serveur". Par exemple : distribution d'artefacts, transmission du code source (quand l'agent ne tĂ©lĂ©charge pas le code directement depuis le dĂ©pĂŽt, mais que le serveur le fait Ă sa place), accĂšs aux logs. Toutes ces tĂąches diffĂšrent par leur charge IO. Cela signifie que le serveur responsable de la logique mĂ©tier complexe doit Ă©galement ĂȘtre capable de gĂ©rer efficacement de grands flux de donnĂ©es. Et ce qui est intĂ©ressant, c'est qu'une telle opĂ©ration peut ĂȘtre dĂ©lĂ©guĂ©e au mĂȘme nginx selon le mĂȘme schĂ©ma (Ă condition d'ajouter une clĂ© de donnĂ©es Ă la requĂȘte).
Cependant, si nous revenons à notre systÚme, nous obtenons un schéma similaire :

Comme vous pouvez le constater, le systĂšme est devenu radicalement plus complexe. Ce nâest plus simplement un mini-processus qui stocke des fichiers localement. Il nĂ©cessite maintenant un support non trivial, un contrĂŽle de version de lâAPI, etc. Il est donc prĂ©fĂ©rable, aprĂšs avoir dessinĂ© tous les diagrammes, dâĂ©valuer en dĂ©tail si lâĂ©volutivitĂ© de telles dĂ©penses en vaut la peine. Cependant, si vous souhaitez ĂȘtre en mesure dâĂ©voluer (y compris pour gĂ©rer un nombre encore plus important dâutilisateurs), vous devrez envisager des solutions de ce type. En revanche, cela rend le systĂšme architecturĂ© prĂȘt Ă une augmentation de la charge (pratiquement chaque composant peut ĂȘtre clonĂ© pour un scaling horizontal). Le systĂšme peut ĂȘtre mis Ă jour sans ĂȘtre arrĂȘtĂ© (simplement, certaines opĂ©rations vont lĂ©gĂšrement ralentir).
Comme je lâai dĂ©jĂ mentionnĂ© au dĂ©but, un certain nombre de services Internet supportent dĂ©sormais une charge accrue. Et certains dâentre eux ont simplement cessĂ© de fonctionner correctement. En effet, les systĂšmes ont Ă©chouĂ© au moment mĂȘme oĂč les entreprises devraient gĂ©nĂ©rer des revenus. Au lieu de livraisons diffĂ©rĂ©es, au lieu de proposer aux clients de 'planifier la livraison pour les mois Ă venir', le systĂšme a simplement dit 'allez voir nos concurrents'. C'est cela le coĂ»t d'une faible performance : les pertes se produisent exactement quand les bĂ©nĂ©fices seraient les plus Ă©levĂ©s.
Conclusion
Tous ces approches Ă©taient dĂ©jĂ connues auparavant. VK utilise depuis longtemps l'idĂ©e de Static Content Hosting pour dĂ©livrer des images. De nombreux jeux en ligne utilisent le schĂ©ma de Sharding pour diviser les joueurs par rĂ©gions ou pour sĂ©parer les zones de jeu (si le monde est unique). Lâapproche dâEvent Sourcing est activement utilisĂ©e dans lâe-mail. La plupart des applications des traders, oĂč les donnĂ©es arrivent en continu, sont en rĂ©alitĂ© construites sur lâapproche CQRS pour pouvoir filtrer les donnĂ©es reçues. De plus, le scaling horizontal est appliquĂ© depuis longtemps dans de nombreux services.
Cependant, ce qui est le plus important, c'est que tous ces patrons sont devenus trĂšs faciles Ă appliquer dans les applications modernes (s'ils sont pertinents, bien sĂ»r). Les clouds proposent le sharding et la mise Ă l'Ă©chelle horizontale immĂ©diatement, ce qui est beaucoup plus facile que de commander diffĂ©rentes serveurs dĂ©diĂ©s dans diffĂ©rents centres de donnĂ©es par soi-mĂȘme. Le CQRS est devenu beaucoup plus simple, rien que grĂące au dĂ©veloppement de bibliothĂšques telles que RX. Il y a 10 ans, un site Web rare aurait pu le supporter. L'event sourcing est Ă©galement configurĂ© incroyablement facilement grĂące Ă des conteneurs prĂȘts Ă l'emploi avec Apache Kafka. Il y a 10 ans, cela aurait Ă©tĂ© une innovation, maintenant c'est une banalitĂ©. Il en va de mĂȘme pour l'hĂ©bergement de contenu statique : grĂące Ă des technologies plus pratiques (notamment parce qu'il existe une documentation dĂ©taillĂ©e et une vaste base de rĂ©ponses), cette approche est devenue encore plus simple.
En fin de compte, la mise en Ćuvre d'un certain nombre de modĂšles architecturaux assez complexes est maintenant beaucoup plus facile, ce qui signifie qu'il vaut mieux y prĂȘter attention Ă l'avance. Si, dans une application vieille de dix ans, on a abandonnĂ© l'une des solutions ci-dessus en raison de son coĂ»t Ă©levĂ© d'implĂ©mentation et d'exploitation, alors maintenant, dans la nouvelle application, ou aprĂšs une refactorisation, on peut crĂ©er un service qui sera dĂ©jĂ extensible sur le plan architectural (en termes de performance) et prĂȘt pour les nouvelles demandes des clients (par exemple, pour la localisation des donnĂ©es personnelles).
Et le plus important : ne utilisez pas ces approches, s'il vous plaĂźt, si vous avez une application simple. Oui, elles sont belles et intĂ©ressantes, mais pour un site avec un pic de 100 visiteurs, on peut souvent se contenter d'un monolithe classique (du moins Ă l'extĂ©rieur, Ă l'intĂ©rieur tout peut ĂȘtre divisĂ© en modules, etc.).
Source : habr.com
