HĂ© Habr !
Ă la lumiĂšre des Ă©vĂ©nements actuels liĂ©s au coronavirus, un certain nombre de services Internet ont commencĂ© Ă recevoir une charge accrue. Par exemple, , parce qu'il n'y avait pas assez de capacitĂ©. Et il nâest pas toujours possible dâaccĂ©lĂ©rer un serveur en ajoutant simplement du matĂ©riel plus puissant, mais les demandes des clients doivent ĂȘtre traitĂ©es (sinon elles iront aux concurrents).
Dans cet article, je parlerai briĂšvement des pratiques populaires qui vous permettront de crĂ©er un service rapide et tolĂ©rant aux pannes. Cependant, parmi les schĂ©mas de dĂ©veloppement possibles, j'ai sĂ©lectionnĂ© uniquement ceux qui sont actuellement facile Ă utiliser. Pour chaque Ă©lĂ©ment, soit vous disposez de bibliothĂšques prĂȘtes Ă l'emploi, soit vous avez la possibilitĂ© de rĂ©soudre le problĂšme Ă l'aide d'une plate-forme cloud.
Mise à l'échelle horizontale
Le point le plus simple et le plus connu. Classiquement, les deux schémas de répartition de charge les plus courants sont la mise à l'échelle horizontale et verticale. vous autorisez les services à s'exécuter en parallÚle, répartissant ainsi la charge entre eux. vous commandez des serveurs plus puissants ou optimisez le code.
Par exemple, je prendrai le stockage de fichiers cloud abstrait, c'est-Ă -dire un analogue de OwnCloud, OneDrive, etc.
Une image standard d'un tel circuit est présentée ci-dessous, mais elle ne fait que démontrer la complexité du systÚme. AprÚs tout, nous devons d'une maniÚre ou d'une autre synchroniser les services. Que se passe-t-il si l'utilisateur enregistre un fichier depuis la tablette et souhaite ensuite le visualiser depuis le téléphone ?

La diffĂ©rence entre les approches : en mise Ă l'Ă©chelle verticale, nous sommes prĂȘts Ă augmenter la puissance des nĆuds, et en mise Ă l'Ă©chelle horizontale, nous sommes prĂȘts Ă ajouter de nouveaux nĆuds pour rĂ©partir la charge.
CQRS
Un modĂšle assez important, puisqu'il permet Ă diffĂ©rents clients non seulement de se connecter Ă diffĂ©rents services, mais Ă©galement de recevoir les mĂȘmes flux d'Ă©vĂ©nements. Ses avantages ne sont pas si Ă©vidents pour une application simple, mais ils sont extrĂȘmement importants (et simples) pour un service trĂšs chargĂ©. Son essence : les flux de donnĂ©es entrants et sortants ne doivent pas se croiser. Autrement dit, vous ne pouvez pas envoyer une requĂȘte et attendre une rĂ©ponse ; Ă la place, vous envoyez une requĂȘte au service A, mais recevez une rĂ©ponse du service B.
Le premier bonus de cette approche est la possibilitĂ© de rompre la connexion (au sens large du terme) tout en exĂ©cutant une requĂȘte longue. Par exemple, prenons une sĂ©quence plus ou moins standard :
- Le client a envoyĂ© une requĂȘte au serveur.
- Le serveur a démarré un long temps de traitement.
- Le serveur a répondu au client avec le résultat.
Imaginons qu'au point 2 la connexion ait été interrompue (ou le réseau s'est reconnecté, ou l'utilisateur est allé sur une autre page, rompant la connexion). Dans ce cas, il sera difficile pour le serveur d'envoyer une réponse à l'utilisateur contenant des informations sur ce qui a été traité exactement. En utilisant 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 « demande acceptée ».
- Le serveur a répondu avec le résultat via le canal du point « 1 ».

Comme vous pouvez le constater, le schĂ©ma est un peu plus compliquĂ©. De plus, lâapproche intuitive demande-rĂ©ponse fait dĂ©faut ici. Cependant, comme vous pouvez le constater, une rupture de connexion lors du traitement dâune requĂȘte nâentraĂźnera pas dâerreur. De plus, si en fait l'utilisateur est connectĂ© au service depuis plusieurs appareils (par exemple, depuis un tĂ©lĂ©phone mobile et depuis une tablette), vous pouvez vous assurer que la rĂ©ponse arrive sur les deux appareils.
Fait intĂ©ressant, le code de traitement des messages entrants devient le mĂȘme (pas Ă 100 %) Ă la fois pour les Ă©vĂ©nements influencĂ©s par le client lui-mĂȘme et pour d'autres Ă©vĂ©nements, y compris ceux d'autres clients.
Cependant, en rĂ©alitĂ©, nous obtenons un bonus supplĂ©mentaire dĂ» au fait que le flux unidirectionnel peut ĂȘtre gĂ©rĂ© de maniĂšre fonctionnelle (en utilisant RX et similaire). Et c'est dĂ©jĂ un sĂ©rieux plus, puisqu'en substance l'application peut ĂȘtre rendue totalement rĂ©active, et Ă©galement en utilisant une approche fonctionnelle. Pour les gros programmes, cela peut Ă©conomiser considĂ©rablement les ressources de dĂ©veloppement et de support.
Si nous combinons cette approche avec une mise Ă l'Ă©chelle horizontale, nous obtenons en prime la possibilitĂ© d'envoyer des requĂȘtes Ă un serveur et de recevoir des rĂ©ponses d'un autre. Ainsi, le client peut choisir le service qui lui convient et le systĂšme interne sera toujours capable de traiter correctement les Ă©vĂ©nements.
Sourcing événementiel
Comme vous le savez, l'une des principales caractĂ©ristiques d'un systĂšme distribuĂ© est l'absence d'heure commune, de section critique commune. Pour un processus, vous pouvez effectuer une synchronisation (sur les mĂȘmes mutex), au sein de laquelle vous ĂȘtes sĂ»r que personne d'autre n'exĂ©cute ce code. Cependant, cela est dangereux pour un systĂšme distribuĂ©, car cela nĂ©cessitera une surcharge et tuera Ă©galement toute la beautĂ© de la mise Ă l'Ă©chelle - tous les composants en attendront toujours une.
De lĂ , nous obtenons un fait important : un systĂšme distribuĂ© rapide ne peut pas ĂȘtre synchronisĂ©, car nous rĂ©duirions alors les performances. En revanche, on a souvent besoin dâune certaine cohĂ©rence entre les composants. Et pour cela, vous pouvez utiliser l'approche avec , oĂč il est garanti que s'il n'y a pas de modification des donnĂ©es pendant un certain temps aprĂšs la derniĂšre mise Ă jour (« Ă©ventuellement »), toutes les requĂȘtes renverront la derniĂšre valeur mise Ă jour.
Il est important de comprendre que pour les bases de donnĂ©es classiques, il est assez souvent utilisĂ© , oĂč chaque nĆud a les mĂȘmes informations (ceci est souvent rĂ©alisĂ© dans le cas oĂč la transaction est considĂ©rĂ©e comme Ă©tablie seulement aprĂšs la rĂ©ponse du deuxiĂšme serveur). Il y a quelques assouplissements ici en raison des niveaux d'isolement, mais l'idĂ©e gĂ©nĂ©rale reste la mĂȘme : vous pouvez vivre dans un monde complĂštement harmonisĂ©.
Cependant, revenons Ă la tĂąche initiale. Si une partie du systĂšme peut ĂȘtre construite avec , alors nous pouvons construire le diagramme suivant.

Caractéristiques importantes de cette approche :
- Chaque demande entrante est placée dans une file d'attente.
- Lors du traitement d'une demande, le service peut également placer des tùches dans d'autres files d'attente.
- Chaque événement entrant possÚde un identifiant (nécessaire à la déduplication).
- La file d'attente fonctionne idéologiquement selon le schéma « ajouter uniquement ». Vous ne pouvez pas en supprimer des éléments ni les réorganiser.
- La file d'attente fonctionne selon le schéma FIFO (désolé pour la tautologie). Si vous devez effectuer une exécution parallÚle, vous devez à un moment donné déplacer les objets vers différentes files d'attente.
Je vous rappelle que nous étudions le cas du stockage de fichiers en ligne. Dans ce cas, le systÚme ressemblera à ceci :

Il est important que les services prĂ©sentĂ©s dans le diagramme ne dĂ©signent pas nĂ©cessairement un serveur distinct. MĂȘme le processus peut ĂȘtre le mĂȘme. Une autre chose est importante : idĂ©ologiquement, ces Ă©lĂ©ments sont sĂ©parĂ©s de telle maniĂšre quâune Ă©chelle horizontale peut ĂȘtre facilement appliquĂ©e.
Et pour deux utilisateurs le schéma ressemblera à ceci (les services destinés à différents utilisateurs sont indiqués dans des couleurs différentes) :

Bonus d'une telle combinaison :
- Les services de traitement de l'information sont séparés. Les files d'attente sont également séparées. Si nous devons augmenter le débit du systÚme, il nous suffit alors de lancer davantage de services sur davantage de serveurs.
- Lorsque nous recevons des informations d'un utilisateur, nous n'avons pas besoin d'attendre que les donnĂ©es soient complĂštement enregistrĂ©es. Au contraire, il suffit de rĂ©pondre « ok » et de commencer progressivement Ă travailler. Dans le mĂȘme temps, la file d'attente attĂ©nue les pics, car l'ajout d'un nouvel objet se produit rapidement et l'utilisateur n'a pas Ă attendre un parcours complet de tout le cycle.
- A titre d'exemple, j'ai ajoutĂ© un service de dĂ©duplication qui tente de fusionner des fichiers identiques. Si cela fonctionne longtemps dans 1% des cas, le client ne s'en apercevra pratiquement pas (voir ci-dessus), ce qui est un gros plus, puisqu'on n'est plus obligĂ© d'ĂȘtre rapide et fiable Ă XNUMX%.
Cependant, les inconvénients sont immédiatement visibles :
- Notre systĂšme a perdu sa stricte cohĂ©rence. Cela signifie que si, par exemple, vous vous abonnez Ă diffĂ©rents services, vous pouvez thĂ©oriquement obtenir un Ă©tat diffĂ©rent (puisque l'un des services peut ne pas avoir le temps de recevoir une notification de la file d'attente interne). Autre consĂ©quence : le systĂšme n'a plus d'heure commune. C'est-Ă -dire qu'il est impossible, par exemple, de trier tous les Ă©vĂ©nements simplement par heure d'arrivĂ©e, puisque les horloges entre serveurs peuvent ne pas ĂȘtre synchrones (d'ailleurs, la mĂȘme heure sur deux serveurs est une utopie).
- Aucun Ă©vĂ©nement ne peut dĂ©sormais ĂȘtre simplement annulĂ© (comme cela pourrait ĂȘtre le cas avec une base de donnĂ©es). Au lieu de cela, vous devez ajouter un nouvel Ă©vĂ©nement - , ce qui changera le dernier Ă©tat en celui requis. A titre d'exemple dans un domaine similaire : sans réécrire l'historique (ce qui est mauvais dans certains cas), vous ne pouvez pas annuler un commit dans git, mais vous pouvez crĂ©er un commit spĂ©cial. , qui renvoie essentiellement l'ancien Ă©tat. Cependant, la validation erronĂ©e et la restauration resteront dans lâhistorique.
- Le schĂ©ma des donnĂ©es peut changer d'une version Ă l'autre, mais les anciens Ă©vĂ©nements ne pourront plus ĂȘtre mis Ă jour vers le nouveau standard (puisque les Ă©vĂ©nements ne peuvent en principe pas ĂȘtre modifiĂ©s).
Comme vous pouvez le constater, Event Sourcing fonctionne bien avec CQRS. De plus, mettre en Ćuvre un systĂšme avec des files d'attente efficaces et pratiques, mais sans sĂ©parer les flux de donnĂ©es, est dĂ©jĂ difficile en soi, car il faudra ajouter des points de synchronisation qui neutraliseront tout l'effet positif des files d'attente. En appliquant les deux approches Ă la fois, il est nĂ©cessaire d'ajuster lĂ©gĂšrement le code du programme. Dans notre cas, lors de l'envoi d'un fichier au serveur, la rĂ©ponse arrive uniquement « ok », ce qui signifie uniquement que « l'opĂ©ration d'ajout du fichier a Ă©tĂ© enregistrĂ©e ». Formellement, cela ne signifie pas que les donnĂ©es sont dĂ©jĂ disponibles sur d'autres appareils (par exemple, le service de dĂ©duplication peut reconstruire l'index). Cependant, aprĂšs un certain temps, le client recevra une notification du style « le fichier X a Ă©tĂ© enregistrĂ© ».
Par conséquent:
- Le nombre de statuts d'envoi de fichiers augmente : au lieu du classique « fichier envoyé », nous en obtenons deux : « le fichier a été ajouté à la file d'attente sur le serveur » et « le fichier a été enregistré en stockage ». Ce dernier signifie que d'autres appareils peuvent déjà commencer à recevoir le fichier (en tenant compte du fait que les files d'attente fonctionnent à des vitesses différentes).
- Ătant donnĂ© que les informations de soumission transitent dĂ©sormais par diffĂ©rents canaux, nous devons trouver des solutions pour connaĂźtre l'Ă©tat de traitement du dossier. ConsĂ©quence de ceci : contrairement Ă la requĂȘte-rĂ©ponse classique, le client peut ĂȘtre redĂ©marrĂ© pendant le traitement du fichier, mais le statut de ce traitement lui-mĂȘme sera correct. De plus, cet article fonctionne essentiellement immĂ©diatement. ConsĂ©quence : nous sommes dĂ©sormais plus tolĂ©rants Ă lâĂ©gard des Ă©checs.
Sharding
Comme dĂ©crit ci-dessus, les systĂšmes de sourcing dâĂ©vĂ©nements manquent de cohĂ©rence stricte. Cela signifie que nous pouvons utiliser plusieurs stockages sans aucune synchronisation entre eux. En abordant notre problĂšme, nous pouvons :
- SĂ©parez les fichiers par type. Par exemple, les images/vidĂ©os peuvent ĂȘtre dĂ©codĂ©es et un format plus efficace peut ĂȘtre sĂ©lectionnĂ©.
- Comptes sĂ©parĂ©s par pays. En raison de nombreuses lois, cela peut ĂȘtre requis, mais ce schĂ©ma d'architecture offre automatiquement une telle opportunitĂ©.

Si vous souhaitez transfĂ©rer des donnĂ©es dâun stockage Ă un autre, alors les moyens standards ne suffisent plus. Malheureusement, dans ce cas, vous devez arrĂȘter la file d'attente, effectuer la migration, puis la dĂ©marrer. Dans le cas gĂ©nĂ©ral, les donnĂ©es ne peuvent pas ĂȘtre transfĂ©rĂ©es « Ă la volĂ©e », cependant, si la file d'attente des Ă©vĂ©nements est entiĂšrement stockĂ©e et que vous disposez d'instantanĂ©s des Ă©tats de stockage prĂ©cĂ©dents, nous pouvons alors rejouer les Ă©vĂ©nements comme suit :
- Dans Event Source, chaque événement possÚde son propre identifiant (idéalement, non décroissant). Cela signifie que nous pouvons ajouter un champ au stockage - l'identifiant 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 est celui dans lequel les donnĂ©es sont dĂ©jĂ stockĂ©es, et le second est nouveau, mais toujours vide). Bien entendu, la deuxiĂšme file dâattente nâest pas encore traitĂ©e.
- Nous lançons la deuxiÚme file d'attente (c'est-à -dire que nous commençons à rejouer les événements).
- Lorsque la nouvelle file d'attente est relativement vide (c'est-à -dire que le délai moyen entre l'ajout d'un élément et sa récupération est acceptable), vous pouvez commencer à faire basculer les lecteurs vers le nouveau stockage.
Comme vous pouvez le constater, nous nâavions pas, et nâavons toujours pas, une cohĂ©rence stricte dans notre systĂšme. Il n'y a qu'une cohĂ©rence Ă©ventuelle, c'est-Ă -dire une garantie que les Ă©vĂ©nements sont traitĂ©s dans le mĂȘme ordre (mais Ă©ventuellement avec des dĂ©lais diffĂ©rents). Et grĂące Ă cela, nous pouvons transfĂ©rer des donnĂ©es relativement facilement sans arrĂȘter le systĂšme Ă lâautre bout du monde.
Ainsi, poursuivant notre exemple sur le stockage de fichiers en ligne, une telle architecture nous apporte déjà un certain nombre de bonus :
- Nous pouvons rapprocher les objets des utilisateurs de maniÚre dynamique. De cette façon, vous pouvez améliorer la qualité du service.
- Nous pouvons stocker certaines données au sein des entreprises. Par exemple, les utilisateurs d'entreprise exigent souvent que leurs données soient stockées dans des centres de données contrÎlés (pour éviter les fuites de données). Grùce au partitionnement, nous pouvons facilement prendre en charge cela. Et la tùche est encore plus facile si le client dispose d'un cloud compatible (par exemple, ).
- Et le plus important câest que nous nâayons pas Ă faire ça. AprĂšs tout, pour commencer, nous serions trĂšs satisfaits d'un seul stockage pour tous les comptes (pour commencer Ă travailler rapidement). Et la principale caractĂ©ristique de ce systĂšme est que, bien quâil soit extensible, il est assez simple au dĂ©but. Vous nâavez tout simplement pas besoin dâĂ©crire immĂ©diatement du code qui fonctionne avec un million de files dâattente indĂ©pendantes distinctes, etc. Si nĂ©cessaire, cela pourra ĂȘtre fait Ă l'avenir.
Hébergement de contenu statique
Ce point peut paraĂźtre assez Ă©vident, mais il reste nĂ©anmoins nĂ©cessaire pour une application chargĂ©e plus ou moins standard. Son essence est simple : tout le contenu statique n'est pas distribuĂ© Ă partir du mĂȘme serveur sur lequel se trouve l'application, mais Ă partir de serveurs spĂ©ciaux dĂ©diĂ©s spĂ©cifiquement Ă cette tĂąche. En consĂ©quence, ces opĂ©rations sont effectuĂ©es plus rapidement (nginx conditionnel sert les fichiers plus rapidement et moins cher qu'un serveur Java). Plus l'architecture CDN () nous permet de localiser nos fichiers plus prĂšs des utilisateurs finaux, ce qui a un effet positif sur la commoditĂ© de travailler avec le service.
Lâexemple le plus simple et le plus standard de contenu statique est un ensemble de scripts et dâimages pour un site Web. Tout est simple avec eux : ils sont connus Ă l'avance, puis les archives sont tĂ©lĂ©chargĂ©es sur des serveurs CDN, d'oĂč elles sont distribuĂ©es aux utilisateurs finaux.
Cependant, en rĂ©alitĂ©, pour le contenu statique, vous pouvez utiliser une approche quelque peu similaire Ă l'architecture lambda. Revenons Ă notre tĂąche (stockage de fichiers en ligne), dans laquelle nous devons distribuer des fichiers aux utilisateurs. La solution la plus simple est de crĂ©er un service qui, pour chaque demande de l'utilisateur, effectue toutes les vĂ©rifications nĂ©cessaires (autorisation, etc.), 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 une certaine rĂ©vision est, en fait, un contenu statique) est distribuĂ© par le mĂȘme serveur qui contient la logique mĂ©tier. A la place, vous pouvez rĂ©aliser le schĂ©ma suivant :
- Le serveur fournit une URL de tĂ©lĂ©chargement. Il peut ĂȘtre de la forme file_id + key, oĂč key est une mini-signature numĂ©rique qui donne le droit d'accĂ©der Ă la ressource pour les prochaines XNUMX heures.
- Le fichier est distribué par simple nginx avec les options suivantes :
- Mise en cache du contenu. Ce service pouvant ĂȘtre localisĂ© sur un serveur sĂ©parĂ©, nous nous sommes laissĂ© une rĂ©serve pour l'avenir avec la possibilitĂ© de stocker sur disque tous les derniers fichiers tĂ©lĂ©chargĂ©s.
- Vérification de la clé au moment de la création de la connexion
- Facultatif : traitement du contenu en streaming. Par exemple, si nous compressons tous les fichiers du service, nous pouvons alors effectuer la dĂ©compression directement dans ce module. En consĂ©quence : les opĂ©rations dâE/S sont effectuĂ©es lĂ oĂč elles doivent ĂȘtre. Un archiveur en Java allouera facilement beaucoup de mĂ©moire supplĂ©mentaire, mais réécrire un service avec une logique mĂ©tier dans des conditions Rust/C++ peut Ă©galement s'avĂ©rer inefficace. Dans notre cas, diffĂ©rents processus (voire services) sont utilisĂ©s, et nous pouvons donc sĂ©parer assez efficacement la logique mĂ©tier et les opĂ©rations d'E/S.

Ce schĂ©ma n'est pas trĂšs similaire Ă la distribution de contenu statique (puisque nous ne tĂ©lĂ©chargeons pas l'intĂ©gralitĂ© du package statique quelque part), mais en rĂ©alitĂ©, cette approche concerne prĂ©cisĂ©ment 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Ă© comme un ensemble de blocs immuables et non supprimables (bien qu'ils puissent ĂȘtre ajoutĂ©s).
Comme autre exemple (Ă titre de renforcement) : si vous avez travaillĂ© avec Jenkins/TeamCity, alors vous savez que les deux solutions sont Ă©crites en Java. Les deux sont un processus Java qui gĂšre Ă la fois lâorchestration des builds et la gestion du contenu. En particulier, ils ont tous deux des tĂąches telles que « transfĂ©rer un fichier/dossier depuis le serveur ». A titre d'exemple : Ă©mission d'artefacts, transfert de code source (lorsque l'agent ne tĂ©lĂ©charge pas le code directement depuis le rĂ©fĂ©rentiel, mais que le serveur le fait pour lui), accĂšs aux logs. Toutes ces tĂąches diffĂšrent par leur charge d'E/S. Autrement dit, il s'avĂšre que le serveur responsable d'une logique mĂ©tier complexe doit en mĂȘme temps ĂȘtre capable de transmettre efficacement de gros flux de donnĂ©es Ă travers lui-mĂȘme. Et ce qui est le plus intĂ©ressant, c'est qu'une telle opĂ©ration peut ĂȘtre dĂ©lĂ©guĂ©e au mĂȘme nginx selon exactement le mĂȘme schĂ©ma (sauf que la clĂ© de donnĂ©es doit ĂȘtre ajoutĂ©e Ă la requĂȘte).
Cependant, si nous revenons Ă notre systĂšme, nous obtenons un diagramme similaire :

Comme vous pouvez le constater, le systĂšme est devenu radicalement plus complexe. DĂ©sormais, il ne s'agit plus simplement d'un mini-processus qui stocke les fichiers localement. DĂ©sormais, ce qui est requis n'est pas le support le plus simple, le contrĂŽle de version de l'API, etc. Par consĂ©quent, une fois tous les diagrammes dessinĂ©s, il est prĂ©fĂ©rable dâĂ©valuer en dĂ©tail si lâextensibilitĂ© en vaut le coĂ»t. Cependant, si vous souhaitez pouvoir Ă©tendre le systĂšme (y compris pour travailler avec un nombre encore plus grand d'utilisateurs), vous devrez alors opter pour des solutions similaires. Mais, par consĂ©quent, le systĂšme est architecturalement prĂȘt pour une charge accrue (presque tous les composants peuvent ĂȘtre clonĂ©s pour une mise Ă l'Ă©chelle horizontale). Le systĂšme peut ĂȘtre mis Ă jour sans l'arrĂȘter (simplement certaines opĂ©rations seront lĂ©gĂšrement ralenties).
Comme je l'ai dit au tout dĂ©but, un certain nombre de services Internet ont commencĂ© Ă recevoir une charge accrue. Et certains dâentre eux ont simplement commencĂ© Ă ne plus fonctionner correctement. En fait, les systĂšmes ont Ă©chouĂ© prĂ©cisĂ©ment au moment oĂč lâentreprise Ă©tait censĂ©e gagner de lâargent. Autrement dit, au lieu de diffĂ©rer la livraison, au lieu de suggĂ©rer aux clients de « planifier votre livraison pour les mois Ă venir », le systĂšme leur disait simplement « allez chez vos concurrents ». En fait, câest le prix dâune faible productivitĂ© : les pertes se produiront prĂ©cisĂ©ment au moment oĂč les profits seraient les plus Ă©levĂ©s.
Conclusion
Toutes ces approches Ă©taient connues auparavant. Le mĂȘme VK utilise depuis longtemps l'idĂ©e de l'hĂ©bergement de contenu statique pour afficher des images. De nombreux jeux en ligne utilisent le systĂšme Sharding pour diviser les joueurs en rĂ©gions ou pour sĂ©parer les emplacements de jeu (si le monde lui-mĂȘme en est un). Lâapproche Event Sourcing est activement utilisĂ©e dans le courrier Ă©lectronique. La plupart des applications de trading oĂč les donnĂ©es sont reçues en permanence sont en fait construites sur une approche CQRS afin de pouvoir filtrer les donnĂ©es reçues. Eh bien, la mise Ă l'Ă©chelle horizontale est utilisĂ©e dans de nombreux services depuis assez longtemps.
Mais surtout, tous ces modĂšles sont devenus trĂšs faciles Ă appliquer dans les applications modernes (sâils sont appropriĂ©s, bien sĂ»r). Les cloud offrent immĂ©diatement le partage et la mise Ă l'Ă©chelle horizontale, ce qui est beaucoup plus simple que de commander vous-mĂȘme diffĂ©rents serveurs dĂ©diĂ©s dans diffĂ©rents centres de donnĂ©es. CQRS est devenu beaucoup plus simple, ne serait-ce que grĂące au dĂ©veloppement de bibliothĂšques telles que RX. Il y a environ 10 ans, un site Web rare pouvait prendre en charge cela. Event Sourcing est Ă©galement incroyablement simple Ă mettre en place grĂące aux conteneurs prĂȘts Ă l'emploi avec Apache Kafka. Il y a 10 ans, cela aurait Ă©tĂ© une innovation, maintenant c'est monnaie courante. C'est la mĂȘme chose avec l'hĂ©bergement de contenu statique : grĂące Ă des technologies plus pratiques (y compris le fait qu'il existe une documentation dĂ©taillĂ©e et une grande base de donnĂ©es de rĂ©ponses), cette approche est devenue encore plus simple.
En consĂ©quence, la mise en Ćuvre d'un certain nombre de modĂšles architecturaux plutĂŽt complexes est dĂ©sormais devenue beaucoup plus simple, ce qui signifie qu'il est prĂ©fĂ©rable de l'examiner de plus prĂšs Ă l'avance. Si dans une application vieille de dix ans l'une des solutions ci-dessus a Ă©tĂ© abandonnĂ©e en raison du coĂ»t Ă©levĂ© de mise en Ćuvre et d'exploitation, maintenant, dans une nouvelle application, ou aprĂšs refactoring, vous pouvez crĂ©er un service qui sera dĂ©jĂ architecturalement Ă la fois extensible ( en termes de performances) et prĂȘt Ă rĂ©pondre aux nouvelles demandes des clients (par exemple pour localiser des donnĂ©es personnelles).
Et surtout : nâutilisez pas ces approches si vous avez une application simple. Oui, ils sont beaux et intĂ©ressants, mais pour un site avec une frĂ©quentation maximale de 100 personnes, on peut souvent se contenter d'un monolithe classique (au moins Ă l'extĂ©rieur, tout Ă l'intĂ©rieur peut ĂȘtre divisĂ© en modules, etc.).
Source: habr.com
