Comment les architectures de système microservice évitent-elles les goulots d'étranglement sur le réseau?


72

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

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

  1. Architecture monolithique: une application dans une seule langue qui gère l’ensemble des fonctionnalités, des données, etc. Un équilibreur de charge distribue les demandes de l’utilisateur final sur plusieurs machines, chacune exécutant une instance de notre application.

  2. Architecture de microservice : 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 à une communication interprocessus ou à une mémoire partagée sur le même ordinateur). Les appels d'API sont généralement stichés sur le serveur pour produire une page, bien qu'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 le même ordinateur (la mémoire et le disque). Comment s'assurer que les requêtes d'API via le réseau interne ne ralentiront pas le temps de réponse global?


Le réseau interne est souvent 1 Gbps, parfois plus rapide. Pensez à la taille moyenne de la réponse JSON d'une API. Combien de ces réponses peuvent être transmises sur une connexion de 1 Gbps en une seconde?
Arseni Mourzenko

3
si vous pensez avoir besoin de microservices - et vous pourriez le faire! - deux excellents livres à préparer: amazon.com/Building-Microservices-Sam-Newman/dp/1491950358 et amazon.com/Release-It-Production-Ready-Pragmatic-Programmers/dp/…
Steven A. Lowe

@MainMa le problème n'est pas dans la bande passante, mais dans le retard. Et si vous avez besoin d'aller-retour, vous seriez surpris du peu de bande passante réelle que vous pouvez utiliser
Stephan Eggermont

Réponses:


61

Les réseaux internes utilisent souvent des connexions 1 Gbit / s ou plus rapides. Les connexions ou liaisons par fibres optiques permettent des largeurs de bande beaucoup plus élevées entre les serveurs. Imaginez maintenant la taille moyenne d'une réponse JSON d'une API. Combien de ces réponses peuvent être transmises sur une connexion de 1 Gbps 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 assez!), Vous pouvez envoyer 26 214 réponses par seconde de bout en bout avec seulement une paire de machines . Pas si mal, n'est ce pas?

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 le consommant. Si jamais la connexion devient un goulot d'étranglement, ajoutez simplement deux autres serveurs et vous pourrez doubler les performances.

C’est à ce moment-là que nos 26 214 réponses précédentes par seconde deviennent trop petites pour l’ampleur de l’application. Vous ajoutez neuf autres paires et vous pouvez maintenant servir 262 140 réponses.

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

  • Si une requête moyenne non mise en cache sur 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, à l'heure actuelle, la page d'accueil de DOMContentLoaded pour Google s'est produite à 394 ms. après l'envoi de la demande. C'est moins de 3 demandes par seconde. Pour la page d’accueil de Programmers.SE, cela s’est passé à 603 ms. après l'envoi de la demande. Ce n'est même pas 2 demandes par seconde. Au fait, j'ai une connexion Internet à 100 Mbps et un ordinateur rapide: beaucoup d'utilisateurs vont attendre 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 devez effectuer les tests de performances et le profilage réels pour déterminer l'emplacement exact du goulot d'étranglement de votre système hébergé sur un matériel particulier). Le temps consacré au travail réel (qu'il s'agisse de requêtes SQL, de compression, etc.) et l'envoi du résultat à l'utilisateur final sont beaucoup plus importants.

Pensez aux bases de données

Généralement, les bases de données sont hébergées séparément de l'application Web qui les utilise. Cela peut poser un problème: 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 que dans certains cas, la vitesse de connexion pose problème, 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 qui devraient être disponibles 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 comparée à 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 plusieurs clients accèdent au NAS 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. D'autres solutions existent, impliquant la réplication de données sur plusieurs NAS.

Oubliez la vitesse; penser à l'évolutivité

Un point important d'une application Web est de pouvoir évoluer. Bien que les performances réelles importent (car personne ne veut payer pour des serveurs plus puissants), l’évolutivité est beaucoup plus importante, car elle vous permet de lancer 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 serez pas en mesure de 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, héberger une application sur un serveur ou sur une machine virtuelle avait 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 constaterez peut-être que la VM est le goulet d'étranglement réel et que, compte tenu de votre taille 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 de la VM est facilement compensé par les avantages de l'abstraction matérielle et de son évolutivité.


Bien sûr, nous pouvons dire que les réponses JSON sont petites, mais qu'en est-il de leur quantité ? J'ai l'impression qu'un site Web soumis à une charge importante générerait davantage de trafic réseau dans une architecture de microservice qu'une architecture monolithique (où le seul trafic réseau provient du / des serveur (s) de base de données). La mise en cache peut aider, mais pour le contenu généré en temps réel et dynamiquement, je ne sais pas jusqu'où irait la mise en cache.
James Mishra

@JamesMishra: J'ai modifié ma réponse pour répondre à vos préoccupations.
Arseni Mourzenko

Votre réponse est parfaite . Non seulement vous avez répondu à toutes les objections auxquelles je peux penser, vous avez également répondu à des objections auxquelles je n'avais pas pensé.
James Mishra

5
Mes deux centimes du monde réel: Un système composé de microservices très bavards peut subir des problèmes de performances uniquement à cause d'un réseau saturé. La mise en cache et une conception basée sur Event Stream est votre ami dans de tels cas. Outre le réseau, le processeur et la mémoire, un système basé sur un microservice doit également intégrer la résilience dans sa conception: que se passe-t-il si un microservice est arrêté? Comment créer des tentatives, des transactions distribuées, l'auto-guérison, la surveillance - Je suggère de chercher "tu dois être aussi grand pour utiliser des microservices"
Sudhanshu Mishra

4
S'il vous plaît, corrigez-moi si je me trompe, mais autant que je sache, si vous avez un réseau 1 Gbps, cela signifie que vous pouvez théoriquement envoyer 1 Gb de données par seconde via ce réseau. Peu importe le nombre de connexions. Plus le nombre de connexions est élevé, plus la bande passante de chaque connexion est faible. Ainsi, votre limite réelle sans mettre à niveau votre réseau pour prendre en charge une bande passante plus élevée serait de 26,214 réponses par seconde. Ajouter plus de serveurs n'augmentera pas la bande passante de votre réseau. Si un seul cluster peut générer autant de trafic, l'ajout de serveurs générant encore plus de données encombrera votre réseau.
Sebbe

7

Je pense que vous lisez trop dans la partie "micro". Cela ne signifie pas que chaque classe doit être remplacée par un service réseau, mais une application monolithique doit être divisée en composants de taille raisonnable, chacun traitant d'un aspect de votre programme. Les services ne se parlent pas, vous pouvez donc, au pire, diviser une requête réseau volumineuse en plusieurs requêtes plus petites. Les données renvoyées ne seront de toute façon pas très différentes de celles que vous recevrez (bien que vous puissiez renvoyer plus de données et les consolider dans le client)


3
"Les services ne se parleront pas." J'imagine que les microservices pourraient avoir des dépendances partagées (authentification, peut-être?) Que l'on pourrait séparer en un autre microservice. En un sens, LDAP est un microservice d’authentification et j’imagine que tous les autres microservices y parlent. Ou ... l'authentification n'est-elle effectuée qu'une fois? Comment chaque microservice vérifie-t-il les autorisations par rapport à l'authentification pour empêcher les attaques par accès direct aux objets?
James Mishra

2
@ JamesMishra bien .. ça dépend. Lors de ma dernière utilisation de l'architecture de microservice, chaque service était totalement indépendant des autres pour des raisons de sécurité (mais également pour des raisons de silo d'entreprise). L'authentification était gérée différemment par chacun, bien que contrôlée par une stratégie d'architecture. Pourtant, il n’existe aucune raison pour laquelle ils ne pourraient pas parler à auth par exemple, ou simplement disposer d’une authentification basée sur une bibliothèque. Mais ... j'essayais de dire qu'ils ne devraient pas passer beaucoup d'appels entre eux, pas qu'ils ne devraient pas consommer de services en tant que clients eux-mêmes.
Gbjbaanb

@JamesMishra, auth est souvent son propre service dans ces environnements, de sorte que chaque service doit simplement l'utiliser, plutôt que de procéder à une implémentation complète.
Paul

2

En structurant votre accès au code et aux ressources de manière à ce que le système résultant puisse être suffisamment souple pour être exécuté en tant qu’application monolithique ou distribuée via une configuration. Si vous éliminez le mécanisme de communication derrière une interface commune et que vous construisez votre système en gardant à l'esprit la simultanéité, vous pouvez facilement tout optimiser après avoir profilé votre système et trouvé les véritables goulots d'étranglement.


Un exemple pour expliquer ce que je suppose que @mortalapeman signifie: vous avez une interface java / c # IProductAvailibitiy à laquelle tous les consommateurs IProductAvailibitiy sont liés. Il existe également une classe ProductAvailibitiyImpl qui implémente cette interface et un ProductAvailibitiyMicroservice qui utilise ProductAvailibitiyImpl. Les consommateurs peuvent être configurés pour utiliser un ProductAvailibitiyImpl local ou un proxy distant pour ProductAvailibitiyMicroservice
k3b le

2

J'aimerais ajouter un point de vue différent, issu d'un secteur différent 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é. Principales différences: tous les joueurs partagent un certain état: où se trouve le dragon actuellement; pas d'appels de base de données; tout est maintenu en 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 comme un monolithe (représentant toutes les facettes d’un joueur) ou comme un microservice (représentant un seul joueur dans une foule).

Mes collègues se sont montrés intéressés à décomposer une seule application participante proprement dite, davantage en microservices plus petits qui pourraient être partagés, par exemple un arbitrage de dommages ou des calculs de ligne de mire, des éléments qui sont généralement intégrés aux simulations.

Le problème est la latence de la distribution des appels et de l'attente des demandes. La bande passante est sans importance et abondante de toute façon, comme d'autres l'ont souligné. Mais si un calcul en visibilité directe passe de 1 microsec à 100 microsecondes (par exemple, en raison de la file d'attente dans le nouveau microservice partagé entre toutes les applications du lecteur), la perte est énorme (il faudra peut-être plusieurs calculs chaque mise à jour, plusieurs mises à jour / seconde).

Réfléchissez très attentivement au fonctionnement des services, à leur appel et aux données échangées. Nos applications n'échangent déjà pas que des informations de position, elles échangent des informations de comptabilisation mortes - je suis à la position x, dans la direction 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 de latence (tout en posant un problème) sont proportionnellement moins fréquentes.

Donc, plutôt que de demander un service avec un 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 des calculs locaux
  2. envoi de paramètres de requête ou de déclencheur pour une réponse asynchrone
  3. demandes en lots
  4. anticiper les demandes et préparer une réponse à l'avance, sur spéculation (au contraire de l'évaluation paresseuse)
  5. dans la mesure du possible, évitez les microservices faisant appel à d’autres microservices; cela aggrave le problème, évidemment. Je comprends que cela incite à agrandir les microservices et à défaire quelque peu l’argument, mais les microservices ne sont pas des amis de la latence. Peut-être juste l'admettre et s'en remettre.

Rappelez-vous maintenant de vérifier vos hypothèses sur votre système. Si vous êtes plus préoccupé par le débit que par le temps de latence, ou si vous n'avez pas d'état partagé, etc., utilisez bien sûr les microservices là où ils ont un sens. Je dis juste peut-être que ne les utilisez pas là où ils n’ont pas de sens.


1

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 micro-services se traduisent par des efforts et des délais de développement et de maintenance.

Et bien sûr, il n’existe aucune règle interdisant l’utilisation de la mémoire partagée ou le déploiement physique de plusieurs services dans un seul exécutable. Tant que vous le concevez pour ne pas dépendre de cela.


Les processeurs sont rapides. La mémoire est rapide. Les SSD sont rapides. Mais les cartes réseau, les routeurs et les commutateurs sont-ils "rapides"? Une autre réponse insiste, mais je ne suis pas sûr.
James Mishra

Il est certainement facile de rencontrer des problèmes de vitesse du réseau. Organisez un service à San Francisco, un autre à Amsterdam et consommez-le à Sydney. Le délai est la clé, pas la bande passante. Alors ne fais pas ça. Et rendre les services aussi grands que logique
Stephan Eggermont

1

Comme beaucoup de gens l'ont mentionné, il ne s'agit pas de goulots d'étranglement du réseau. C'est plus une question de fragilité du réseau. La première étape consiste donc à éviter les communications synchrones. C'est plus facile que ça en a l'air. Tout ce dont vous avez besoin, c'est des services avec de bonnes limites. Des frontières justes font que les services sont autonomes, faiblement couplés et très cohérents. Un bon service n'a pas besoin d'informations d'un autre service, il les a déjà. Les bons services ne peuvent communiquer que par des événements. Les bons services finissent également par être cohérents, il n'y a donc pas de transactions distribuées.

Pour parvenir à ce résultat, vous devez d'abord identifier les capacités de votre entreprise. La capacité métier est une responsabilité métier spécifique. Une certaine contribution à la valeur commerciale globale. Voici donc ma séquence de pas que je fais en pensant aux limites du système:

  1. Identifiez les responsabilités professionnelles de niveau supérieur. Il y en aura quelques uns. Traitez ces services comme des étapes que votre organisation devrait franchir pour atteindre son objectif commercial.
  2. Plongez plus profondément dans chaque service. Identifiez les services de niveau inférieur comprenant un service parent.
  3. Parallèlement aux deux premiers points, pensez à la communication de service. Ils doivent le faire principalement via des événements, simplement pour se communiquer les résultats de leurs processus métier. Les événements ne doivent pas être considérés comme des transporteurs de données.

N'oubliez pas que les services métier incluent les personnes, les applications et les processus métier. Habituellement, seule une partie de celle-ci est représentée en tant qu'autorité technique.

Cela peut sembler un peu abstrait, un exemple d’identification des limites de service serait probablement intéressant.


0

Juste un autre facteur à ajouter aux réponses actuelles. Avec des services à grain grossier . Vous voulez éviter la latence de tous les appels. Ainsi, au lieu de faire 10 appels, vous effectuez un appel qui obtient 10 éléments de données nécessaires à un DTO.

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.