ModĂšles architecturaux pratiques

Salut, Habr !

À la lumiĂšre des Ă©vĂ©nements actuels liĂ©s au coronavirus, plusieurs services en ligne font face Ă  une charge accrue. Par exemple, une des chaĂźnes de magasins au Royaume-Uni a simplement arrĂȘtĂ© son site de commandes en ligne,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. Dans le premier cas, vous permettez aux services de fonctionner en parallÚle, répartissant ainsi la charge entre eux. Dans le second, 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 ?

ModĂšles architecturaux pratiques
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

Command Query Responsibility Segregation 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 :

  1. Le client a envoyĂ© une requĂȘte au serveur.
  2. Le serveur a lancé un traitement long.
  3. 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 :

  1. Le client s'est abonné aux mises à jour.
  2. Le client a envoyĂ© une requĂȘte au serveur.
  3. Le serveur a rĂ©pondu « requĂȘte reçue ».
  4. Le serveur a répondu avec le résultat via le canal du point « 1 ».

ModĂšles architecturaux pratiques

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 la cohĂ©rence Ă©ventuelle, 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 cohĂ©rence stricteest 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 la cohĂ©rence Ă©ventuelle, alors on peut construire le schĂ©ma suivant.

ModĂšles architecturaux pratiques

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 :

ModĂšles architecturaux pratiques

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) :

ModĂšles architecturaux pratiques

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 — compensation event, 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 rollback commit, 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.

ModĂšles architecturaux pratiques

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, Azure self hosted).
  • 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 (RĂ©seau de Distribution de Contenu) 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.

ModĂšles architecturaux pratiques

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 :

ModĂšles architecturaux pratiques

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

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster