web-dev-qa-db-fra.com

Comment les architectures de systèmes de microservices évitent-elles les goulots d'étranglement du réseau?

J'ai beaucoup lu sur les architectures de microservices pour les applications serveur, et je me suis demandé comment l'utilisation du réseau interne n'est pas un goulot d'étranglement ou un inconvénient important par rapport à une architecture monolithique.

Par souci de précision, voici mes interprétations des deux termes:

  1. architecture Monolith: Une application dans un seul langage qui gère toutes les fonctionnalités, les données, etc. Un équilibreur de charge répartit les demandes de l'utilisateur final sur plusieurs machines, chacune exécutant une instance de notre application.

  2. Architecture de microservices: De nombreuses applications (microservices) gèrent une petite partie des fonctionnalités et des données. Chaque microservice expose une API commune accessible via le réseau (par opposition à la communication interprocessus ou à la mémoire partagée sur la même machine). Les appels d'API sont concentrés principalement sur le serveur pour produire une page, bien que peut-être une partie de ce travail soit effectuée par le client interrogeant des microservices individuels.

À mon imagination naïve, il semble qu'une architecture de microservices utilise un trafic réseau lent par opposition à des ressources plus rapides sur la même machine (la mémoire et le disque). Comment s'assurer que les requêtes d'API via le réseau interne ne ralentissent pas le temps de réponse global?

74
James Mishra

Les réseaux internes utilisent souvent des connexions à 1 Gbit/s ou plus. Les connexions ou liaisons par fibre optique permettent des bandes passantes beaucoup plus élevées entre les serveurs. Imaginez maintenant la taille moyenne d'une réponse JSON à partir d'une API. Combien de ces réponses peuvent être transmises sur une connexion à 1 Gbit/s en une seconde?

Faisons le calcul. 1 Gbps est de 131 072 Ko par seconde. Si une réponse JSON moyenne est de 5 Ko (ce qui est beaucoup!), vous pouvez envoyer 26 214 réponses par seconde via le fil avec juste une paire de machines. Pas si mal, non?

C'est pourquoi la connexion réseau n'est généralement pas le goulot d'étranglement.

Un autre aspect des microservices est que vous pouvez facilement évoluer. Imaginez deux serveurs, l'un hébergeant l'API, l'autre en consommant. Si jamais la connexion devient le goulot d'étranglement, ajoutez simplement deux autres serveurs et vous pouvez doubler les performances.

C'est alors que nos 26 214 réponses par seconde deviennent trop petites pour l'échelle de l'application. Vous ajoutez neuf autres paires et vous êtes désormais en mesure de fournir 262 140 réponses.

Mais revenons à notre paire de serveurs et faisons quelques comparaisons.

  • Si une requête moyenne non mise en cache dans une base de données prend 10 ms., Vous êtes limité à 100 requêtes par seconde. 100 requêtes. 26 214 réponses. Atteindre la vitesse de 26 214 réponses par seconde nécessite une grande quantité de mise en cache et d'optimisation (si la réponse doit réellement faire quelque chose d'utile, comme interroger une base de données; les réponses de style "Hello World" ne sont pas admissibles).

  • Sur mon ordinateur, en ce moment, DOMContentLoaded pour la page d'accueil de Google s'est produit 394 ms. après l'envoi de la demande. C'est moins de 3 requêtes par seconde. Pour la page d'accueil de Programmers.SE, il s'est produit 603 ms. après l'envoi de la demande. Ce n'est même pas 2 requêtes par seconde. Soit dit en passant, j'ai une connexion Internet à 100 Mbps et un ordinateur rapide: de nombreux utilisateurs attendront plus longtemps.

    Si le goulot d'étranglement est la vitesse du réseau entre les serveurs, ces deux sites pourraient littéralement faire des milliers d'appels vers différentes API tout en servant la page.

Ces deux cas montrent que le réseau ne sera probablement pas votre goulot d'étranglement en théorie (en pratique, vous devriez faire les benchmarks et le profilage réels pour déterminer l'emplacement exact du goulot d'étranglement de votre système particulier hébergé sur un matériel particulier). Le temps passé à faire le travail réel (qu'il s'agisse de requêtes SQL, de compression, etc.) et d'envoyer le résultat à l'utilisateur final est beaucoup plus important.

Pensez aux bases de données

Habituellement, les bases de données sont hébergées séparément de l'application Web qui les utilise. Cela peut soulever une préoccupation: qu'en est-il de la vitesse de connexion entre le serveur hébergeant l'application et le serveur hébergeant la base de données?

Il semble qu'il y ait des cas où, en effet, la vitesse de connexion devient problématique, c'est-à-dire lorsque vous stockez d'énormes quantités de données qui n'ont pas besoin d'être traitées par la base de données elle-même et devraient être disponibles à droite maintenant (c'est-à-dire de gros fichiers binaires). Mais de telles situations sont rares: dans la plupart des cas, la vitesse de transfert n'est pas si grande par rapport à la vitesse de traitement de la requête elle-même.

Lorsque la vitesse de transfert est réellement importante, c'est lorsqu'une entreprise héberge de grands ensembles de données sur un NAS et que le NAS est accessible par plusieurs clients en même temps. C'est là qu'un SAN peut être une solution. Ceci étant dit, ce n'est pas la seule solution. Les câbles Cat 6 peuvent supporter des vitesses allant jusqu'à 10 Gbps; la liaison peut également être utilisée pour augmenter la vitesse sans changer les câbles ou les adaptateurs réseau. Autre des solutions existent, impliquant la réplication des données sur plusieurs NAS.

Oubliez la vitesse; pensez à l'évolutivité

Un point important d'une application Web est de pouvoir évoluer. Alors que les performances réelles sont importantes (car personne ne veut payer pour des serveurs plus puissants), l'évolutivité est beaucoup plus importante, car elle vous permet de jeter du matériel supplémentaire en cas de besoin.

  • Si vous avez une application pas particulièrement rapide, vous perdrez de l'argent car vous aurez besoin de serveurs plus puissants.

  • Si vous avez une application rapide qui ne peut pas évoluer, vous perdrez des clients car vous ne pourrez pas répondre à une demande croissante.

De la même manière, les machines virtuelles étaient perçues il y a une décennie comme un énorme problème de performances. En effet, l'hébergement d'une application sur un serveur par rapport à son hébergement sur une machine virtuelle a eu un impact important sur les performances. Bien que l'écart soit beaucoup plus petit aujourd'hui, il existe toujours.

Malgré cette perte de performances, les environnements virtuels sont devenus très populaires en raison de la flexibilité qu'ils offrent.

Comme avec la vitesse du réseau, vous pouvez constater que VM est le goulot d'étranglement réel et compte tenu de votre échelle réelle, vous économiserez des milliards de dollars en hébergeant votre application directement, sans les VM. Mais ce n'est pas ce qui se passe pour 99,9% des applications: leur goulot d'étranglement est ailleurs, et l'inconvénient d'une perte de quelques microsecondes à cause du VM est facilement compensé par les avantages de l'abstraction matérielle et de l'évolutivité.

63
Arseni Mourzenko

Je pense que vous lisez trop dans la partie "micro". Cela ne signifie pas de remplacer chaque classe par un service réseau, mais de segmenter une application monolithique en composants de taille raisonnable, chacun traitant d'un aspect de votre programme. Les services ne se parlent pas, donc au pire vous avez divisé une grande demande de réseau en plusieurs plus petites. Les données retournées ne seront pas significativement différentes de ce que vous recevrez de toute façon (bien que vous puissiez retourner plus de données et les consolider dans le client)

7
gbjbaanb

En structurant votre code et l'accès aux ressources de sorte que le système résultant puisse être suffisamment flexible pour fonctionner comme une application monolithique ou distribuée via la configuration. Si vous éloignez le mécanisme de communication derrière une interface commune et que vous construisez votre système avec la simultanéité à l'esprit, vous pouvez facilement tout optimiser après avoir profilé votre système et trouvé les vrais goulots d'étranglement.

2
mortalapeman

Comme beaucoup de gens l'ont mentionné, il ne s'agit pas de goulots d'étranglement du réseau. Il s'agit davantage de fragilité du réseau. La première étape consiste donc à éviter la communication synchrone. C'est plus simple qu'il n'y paraît. Tout ce dont vous avez besoin, c'est de services avec de bonnes limites. De bonnes frontières font que les services sont autonomes, faiblement couplés et hautement cohésifs. Un bon service n'a pas besoin d'informations d'un autre service, il les a déjà. La seule façon dont les bons services communiquent est via les événements. De bons services sont finalement cohérents également, il n'y a donc pas de transactions distribuées.

La façon d'atteindre cette qualité est d'identifier d'abord vos capacités commerciales. La capacité commerciale est une responsabilité commerciale spécifique. Une certaine contribution à la valeur commerciale globale. Voici donc ma séquence de pas que je prends quand je pense aux limites du système:

  1. Identifier les responsabilités commerciales de niveau supérieur. Il y en aura quelques-uns. Traitez ces services comme des étapes que votre organisation doit suivre pour atteindre son objectif commercial.
  2. Approfondissez chaque service. Identifier les services de niveau inférieur comprenant un parent.
  3. Parallèlement aux deux premiers points, pensez à la communication sur les services. Ils doivent le faire principalement via des événements, juste pour s'informer mutuellement du résultat de leur processus métier. Les événements ne doivent pas être considérés comme des transporteurs de données.

Gardez à l'esprit que le service métier comprend les personnes, les applications et les processus métier. Habituellement, seule une partie de celui-ci est représentée comme autorité technique.

Cela pourrait sembler un peu abstrait, donc probablement un exemple d'identification des limites de service serait d'un certain intérêt.

2
Zapadlo

Je voudrais ajouter une perspective différente, d'une industrie différente avec des hypothèses très différentes - la simulation distribuée (au niveau de l'entité). Conceptuellement, cela ressemble beaucoup à un jeu vidéo FPS distribué. Différences clés: tous les joueurs partagent un état: où se trouve le dragon en ce moment; aucun appel à la base de données; tout est contenu dans RAM pour la vitesse et la faible latence, le débit est moins pertinent (mais je suppose que vous ne pouvez pas l'ignorer complètement non plus).

Vous pouvez considérer chaque application participante soit comme un monolithe (qui représente toutes les facettes d'un joueur), soit comme un microservice (qui ne représente qu'un seul joueur dans une foule).

Il y a eu un intérêt de mes collègues à décomposer une seule application participante elle-même, plus loin en microservices plus petits qui pourraient être partagés, par exemple endommager l'arbitrage ou les calculs en ligne de visée, des éléments qui sont généralement regroupés dans les simulations.

Le problème est la latence de l'envoi des appels et de l'attente des demandes. La bande passante est de toute façon hors de propos et abondante, comme d'autres l'ont souligné. Mais si un calcul en ligne de vue passe de 1 microsec à 100 microsec (par exemple, en raison de la mise en file d'attente dans le nouveau microservice partagé entre toutes les applications de joueur), c'est une perte énorme (peut nécessiter plusieurs ou plusieurs calculs de ligne de vue pour chaque mise à jour, plusieurs mises à jour/seconde).

Réfléchissez bien au fonctionnement des services, à leur date d'appel et aux données échangées. Nos applications n'échangent pas déjà uniquement des informations de position, elles échangent des informations de calcul à plat - je suis en position x, en direction de y à la vitesse q. Et je n'ai pas à mettre à jour mes informations jusqu'à ce que ces hypothèses changent. Beaucoup moins de mises à jour et la latence (tout en restant un problème) est proportionnellement moins fréquente.

Donc, plutôt que de demander un service à grain fin à une fréquence plus élevée, essayez de réduire la fréquence en:

  1. changer les données demandées et utiliser les calculs locaux
  2. envoi de paramètres de requête ou de déclenchement pour une réponse asynchrone
  3. demandes de traitement par lots
  4. anticiper les demandes et préparer une réponse à l'avance, sur la spéculation (à l'opposé de l'évaluation paresseuse)
  5. dans la mesure du possible, évitez que les microservices appellent d'autres microservices; cela aggrave le problème, évidemment. Je comprends que c'est une incitation à agrandir les microservices et à quelque peu contredire le point, mais les microservices ne sont pas amis de la latence. Peut-être juste l'admettre et s'en remettre.

N'oubliez pas de vérifier vos hypothèses sur votre système. Si vous êtes plus préoccupé par le débit que par la latence, ou si vous n'avez pas d'état partagé, etc., alors, par tous les moyens, utilisez des microservices là où ils ont du sens. Je dis juste que peut-être ne les utilisez pas là où cela n'a pas de sens.

2
Captain Aporam

Votre imagination naïve a raison. Et souvent, cela n'a pas d'importance. Les machines modernes sont rapides. Les principaux avantages de l'architecture de microservices se manifestent dans les efforts et le temps de développement et de maintenance.

Et bien sûr, aucune règle ne dit que vous ne pouvez pas utiliser la mémoire partagée ni même déployer physiquement plusieurs services dans un seul exécutable. Tant que vous le concevez pour ne pas en dépendre.

1

Juste un autre facteur à ajouter aux réponses actuelles. Avec un services à gros grains . Vous voulez éviter la latence de tous les appels, donc au lieu de faire 10 appels, vous effectuez un appel qui obtient 10 données nécessaires dans un DTO.

Et rappelez-vous que les microservices ne sont pas aussi micro que les gens le pensent.

0
Borjab