Netramesh – une solution de service mesh lĂ©ger

Dans le processus de transition d'une application monolithique vers une architecture microservices, nous faisons face à de nouveaux défis.

Dans une application monolithique, il est gĂ©nĂ©ralement suffisamment simple de dĂ©terminer quelle partie du systĂšme a rencontrĂ© une erreur. Il est probable que le problĂšme provienne du code du monolithe lui-mĂȘme ou de la base de donnĂ©es. Mais quand nous commençons Ă  rechercher un problĂšme dans une architecture microservices, ce n’est plus aussi Ă©vident. Il faut retrouver tout le chemin que la requĂȘte a parcouru du dĂ©but Ă  la fin, en le distinguant parmi des centaines de microservices. De plus, beaucoup d'entre eux disposent de leurs propres stockages, oĂč des erreurs logiques, ainsi que des problĂšmes de performance et de rĂ©silience, peuvent Ă©galement survenir.

Netramesh – une solution de service mesh lĂ©ger

J'ai longtemps cherchĂ© un outil qui pourrait aider Ă  rĂ©soudre ces problĂšmes (j'en ai parlĂ© sur Habr : 1, 2), mais j'ai finalement dĂ©veloppĂ© ma propre solution open-source. Dans cet article, je parle des avantages de l'approche service mesh et je partage un nouvel outil pour sa mise en Ɠuvre.

Le tracing distribuĂ© est une solution courante au problĂšme de recherche d'erreurs dans les systĂšmes distribuĂ©s. Mais que se passe-t-il si cette approche pour collecter des informations sur les interactions rĂ©seau n'est pas encore mise en Ɠuvre dans le systĂšme, ou, ce qui est pire, qu'elle fonctionne correctement dans une partie du systĂšme mais pas dans l'autre, car elle n'a pas Ă©tĂ© ajoutĂ©e aux anciens services ? Pour dĂ©terminer la vĂ©ritable cause profonde du problĂšme, il est essentiel d'avoir une vue d'ensemble de ce qui se passe dans le systĂšme. Il est particuliĂšrement important de comprendre quels microservices participent aux parcours critiques pour l'entreprise.

Ici, l'approche service mesh peut nous ĂȘtre utile, car elle s'occupe de toute la machinerie de collecte d'informations rĂ©seau Ă  un niveau infĂ©rieur Ă  celui oĂč fonctionnent les services eux-mĂȘmes. Cette approche nous permet d'intercepter tout le trafic et de l'analyser Ă  la volĂ©e. De plus, les applications n'ont mĂȘme pas besoin d'en ĂȘtre conscientes.

Approche service mesh

L'idĂ©e principale de l'approche du service mesh est d'ajouter une couche d'infrastructure supplĂ©mentaire au-dessus du rĂ©seau, ce qui nous permettra d'effectuer diverses opĂ©rations sur l'interaction entre services. La plupart des implĂ©mentations fonctionnent de la maniĂšre suivante : Ă  chaque microservice, on ajoute un conteneur sidecar supplĂ©mentaire avec un proxy transparent, par lequel tout le trafic entrant et sortant du service transite. C'est Ă  cet endroit prĂ©cis que nous pouvons effectuer l'Ă©quilibrage des clients, appliquer des politiques de sĂ©curitĂ©, imposer des limites sur le nombre de requĂȘtes, et collecter des informations importantes sur les interactions entre services en production.

Netramesh – une solution de service mesh lĂ©ger

Solutions

Il existe dĂ©jĂ  plusieurs implĂ©mentations de cette approche : Istio et linkerd2. Elles offrent de nombreuses fonctionnalitĂ©s prĂȘtes Ă  l'emploi. Mais en mĂȘme temps, cela entraĂźne Ă©galement un important overhead en termes de ressources. En effet, plus le cluster dans lequel cette systĂšme fonctionne est grand, plus les ressources nĂ©cessaires pour maintenir la nouvelle infrastructure seront Ă©levĂ©es. Chez Avito, nous exploitons des clusters Kubernetes qui contiennent des milliers d'instances de services (et leur nombre continue de croĂźtre rapidement). Dans l'implĂ©mentation actuelle, Istio consomme environ 300 Mo de mĂ©moire vive par instance de service. En raison de la multitude de fonctionnalitĂ©s, l'Ă©quilibrage transparent influence Ă©galement le temps de rĂ©ponse global des services (jusqu'Ă  10 ms).

En fin de compte, nous avons examinĂ© les fonctionnalitĂ©s dont nous avons besoin immĂ©diatement et avons dĂ©cidĂ© que la principale raison pour laquelle nous avons commencĂ© Ă  introduire de telles solutions Ă©tait la capacitĂ© de collecter des informations de tracing de maniĂšre transparente Ă  travers l'ensemble du systĂšme. Nous voulions Ă©galement avoir le contrĂŽle sur les interactions entre services et effectuer diffĂ©rentes manipulations des en-tĂȘtes Ă©changĂ©s entre les services.

Finalement, nous sommes arrivés à notre solution : Netramesh.

Netramesh

Netramesh — c'est une solution service mesh lĂ©gĂšre avec une capacitĂ© de mise Ă  l'Ă©chelle infinie, peu importe le nombre de services dans le systĂšme.

Les principaux objectifs de cette nouvelle solution étaient un faible overhead en ressources et une haute performance. Parmi les fonctionnalités principales, nous voulions immédiatement avoir la possibilité d'envoyer de maniÚre transparente les spans de tracing dans notre systÚme Jaeger.

Aujourd'hui, la plupart des solutions cloud sont mises en Ɠuvre en Golang. Et, bien sĂ»r, il y a de bonnes raisons Ă  cela. Écrire des applications rĂ©seau en Golang, qui fonctionnent de maniĂšre asynchrone avec des entrĂ©es-sorties et qui se mettent Ă  l'Ă©chelle en fonction des besoins, est pratique et relativement simple. Et ce qui est Ă©galement trĂšs important, c'est que les performances sont suffisantes pour accomplir cette tĂąche. C'est pourquoi nous avons Ă©galement choisi Golang.

Performance

Nous avons concentrĂ© nos efforts sur l'atteinte d'une performance maximale. Pour une solution dĂ©ployĂ©e Ă  proximitĂ© de chaque instance de service, une faible consommation de mĂ©moire vive et de temps processeur est nĂ©cessaire. Et, bien sĂ»r, la latence de rĂ©ponse doit Ă©galement ĂȘtre minimale.

Voyons quels résultats nous avons obtenus.

RAM

Netramesh consomme environ 10 Mo sans trafic et jusqu'Ă  50 Mo avec une charge allant jusqu'Ă  10 000 RPS sur une seule instance.

Le proxy Istio envoy consomme toujours environ 300 Mo dans nos clusters avec des milliers d'instances. Cela empĂȘche de le redimensionner Ă  l'Ă©chelle du cluster.

Netramesh – une solution de service mesh lĂ©ger

Netramesh – une solution de service mesh lĂ©ger

Avec Netramesh, nous avons réussi à réduire la consommation de mémoire d'environ 10 fois.

CPU

L'utilisation du CPU est relativement Ă©gale sous charge. Elle dĂ©pend du nombre de requĂȘtes par unitĂ© de temps au sidecar. Les valeurs au pic de 3000 requĂȘtes par seconde sont :

Netramesh – une solution de service mesh lĂ©ger

Netramesh – une solution de service mesh lĂ©ger

Il y a un autre point important : Netramesh est une solution sans plan de contrĂŽle et ne consomme pas de temps processeur en l'absence de charge. Avec Istio, les sidecars mettent toujours Ă  jour les endpoints des services. En fin de compte, nous pouvons voir une telle image sans charge :

Netramesh – une solution de service mesh lĂ©ger

Nous utilisons HTTP/1 pour l'interaction entre les services. L'augmentation du temps de rĂ©ponse avec Istio lors du proxying via envoy Ă©tait de 5 Ă  10 ms, ce qui est assez Ă©levĂ© pour des services qui sont prĂȘts Ă  rĂ©pondre en millisecondes. Avec Netramesh, ce temps a Ă©tĂ© rĂ©duit Ă  0,5-2 ms.

Scalabilité

Le faible nombre de ressources utilisées par chaque proxy permet de le placer à cÎté de chaque service. Netramesh a été délibérément conçu sans composant de plan de contrÎle pour maintenir la légÚreté de chaque sidecar. Dans les solutions de service mesh, le plan de contrÎle diffuse souvent les informations de découverte de services dans chaque sidecar. Avec cela arrivent également des informations sur les délais d'attente et les réglages d'équilibrage. Tout cela permet de faire beaucoup de choses utiles, mais, malheureusement, gonfle la taille des sidecars.

Découverte de services

Netramesh – une solution de service mesh lĂ©ger

Netramesh n'ajoute aucun mécanisme supplémentaire pour la découverte de services. Tout le trafic est transparent via le sidecar netra.

Netramesh prend en charge le protocole applicatif HTTP/1. Pour sa dĂ©finition, une liste de ports configurables est utilisĂ©e. En gĂ©nĂ©ral, il existe plusieurs ports dans le systĂšme qui permettent l'interaction via HTTP. Par exemple, pour l'interaction entre services et requĂȘtes externes, nous utilisons les ports 80, 8890, 8080. Dans ce cas, ils peuvent ĂȘtre spĂ©cifiĂ©s Ă  l'aide d'une variable d'environnement. NETRA_HTTP_PORTS.

Si vous utilisez Kubernetes comme orchestrateur et son mĂ©canisme Service pour l'interaction intra-cluster entre services, le mĂ©canisme reste exactement le mĂȘme. Le micro-service obtient d'abord l'adresse IP du service via kube-dns et ouvre une nouvelle connexion vers celle-ci. Cette connexion est Ă©tablie d'abord avec le netra-sidecar local et tous les paquets TCP arrivent initialement dans netra. Ensuite, netra-sidecar Ă©tablit la connexion avec le point de destination initial. Le NAT sur l'adresse IP du pod sur le nƓud reste le mĂȘme que sans netra.

Traçage distribué et transmission de contexte

Netramesh fournit la fonctionnalitĂ© nĂ©cessaire pour envoyer des spans de traçage concernant les interactions HTTP. Netra-sidecar analyse le protocole HTTP, mesure les latences des requĂȘtes et extrait les informations nĂ©cessaires des en-tĂȘtes HTTP. Nous obtenons finalement tous les traçages dans un systĂšme Jaeger unique. Pour une configuration fine, il est Ă©galement possible d'utiliser les variables d'environnement fournies par la bibliothĂšque officielle. bibliothĂšque jaeger go.

Netramesh – une solution de service mesh lĂ©ger

Netramesh – une solution de service mesh lĂ©ger

Cependant, il existe un problĂšme. Tant que les services ne gĂ©nĂšrent pas et ne transmettent pas un en-tĂȘte uber spĂ©cial, nous ne verrons pas les spans de traçage connectĂ©s dans le systĂšme. Et c'est ce qui est nĂ©cessaire pour identifier rapidement les causes des problĂšmes. Ici, Netramesh a Ă  nouveau une solution. Les proxies lisent les en-tĂȘtes HTTP et, en l'absence de l'uber trace id, le gĂ©nĂšrent. Netramesh conserve Ă©galement des informations sur les requĂȘtes entrantes et sortantes dans le sidecar et les associe en enrichissant les nĂ©cessitĂ©s des en-tĂȘtes des requĂȘtes sortantes. Tout ce que les services doivent faire est de transmettre un seul en-tĂȘte. X-Request-Id, qui peut ĂȘtre configurĂ© Ă  l'aide d'une variable d'environnement. NETRA_HTTP_REQUEST_ID_HEADER_NAME. Pour gĂ©rer la taille du contexte dans Netramesh, vous pouvez spĂ©cifier les variables d'environnement suivantes : NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS (le temps pendant lequel le contexte sera conservĂ©) et NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL (la frĂ©quence de nettoyage du contexte).

Il est Ă©galement possible de combiner plusieurs chemins dans votre systĂšme en les marquant avec un marqueur de session spĂ©cial. Netra permet de dĂ©finir HTTP_HEADER_TAG_MAP pour transformer les en-tĂȘtes HTTP en balises de tracing span correspondantes. Cela peut ĂȘtre particuliĂšrement utile pour les tests. AprĂšs avoir effectuĂ© un test fonctionnel, vous pouvez voir quelle partie du systĂšme a Ă©tĂ© affectĂ©e en filtrant par la clĂ© de session correspondante.

Définition de la source de la demande

Pour dĂ©terminer d'oĂč provient la demande, vous pouvez utiliser la fonctionnalitĂ© d'ajout automatique d'en-tĂȘte avec la source. GrĂące Ă  la variable d'environnement NETRA_HTTP_X_SOURCE_HEADER_NAME vous pouvez dĂ©finir le nom de l'en-tĂȘte qui sera automatiquement ajoutĂ©. Avec NETRA_HTTP_X_SOURCE_VALUE vous pouvez dĂ©finir la valeur qui sera attribuĂ©e Ă  l'en-tĂȘte X-Source pour toutes les demandes sortantes.

Cela permet d'uniformiser la diffusion de cet en-tĂȘte utile Ă  travers le rĂ©seau. Ensuite, vous pouvez l'utiliser dans les services et l'ajouter aux journaux, aux mĂ©triques.

Routage du trafic et entrailles de Netramesh

Netramesh est composé de deux principaux composants. Le premier, netra-init, définit les rÚgles de réseau pour intercepter le trafic. Il utilise les rÚgles iptables redirect pour intercepter tout ou partie du trafic vers le sidecar, qui est le deuxiÚme composant principal de Netramesh. Vous pouvez configurer les ports à intercepter pour les sessions TCP entrantes et sortantes : INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS.

L'outil dispose Ă©galement d'une fonctionnalitĂ© intĂ©ressante — le routage probabiliste. Si vous utilisez Netramesh uniquement pour collecter des tracing spans, vous pouvez Ă©conomiser des ressources en production en activant le routage probabiliste Ă  l'aide des variables NETRA_INBOUND_PROBABILITY et NETRA_OUTBOUND_PROBABILITY (de 0 Ă  1). La valeur par dĂ©faut est 1 (tout le trafic est interceptĂ©).

AprÚs une interception réussie, le sidecar netra accepte une nouvelle connexion et utilise SO_ORIGINAL_DST l'option de socket pour obtenir le point de destination d'origine. Ensuite, Netra ouvre une nouvelle connexion à l'adresse IP d'origine et établit une communication TCP bidirectionnelle entre les parties, écoutant tout le trafic passant. Si le port est défini comme HTTP, Netra tente de l'analyser et de le tracer. Si l'analyse HTTP échoue, Netra effectue un fallback sur TCP et proxy les octets de maniÚre transparente.

Construction d'un graphique de dépendances

AprÚs avoir obtenu une grande quantité d'informations de tracing dans Jaeger, on souhaite obtenir un graphique complet des interactions dans le systÚme. Mais si votre systÚme est suffisamment chargé et qu'au cours de la journée des milliards de spans de tracing s'accumulent, leur agrégation devient une tùche compliquée. Il existe une méthode officielle pour cela : spark-dependencies. Cependant, cela prendra des heures pour construire le graphique complet et nécessitera de télécharger l'ensemble du dataset de Jaeger pour les derniÚres 24 heures.

Si vous utilisez Elasticsearch pour stocker les spans de tracing, vous pouvez utiliser un utilitaire simple en Golang, qui construira un graphique similaire en quelques minutes, en exploitant les caractéristiques et les fonctionnalités d'Elasticsearch.

Netramesh – une solution de service mesh lĂ©ger

Comment utiliser Netramesh

Netra peut ĂȘtre facilement ajoutĂ© Ă  n'importe quel service exĂ©cutĂ© sous un orchestrateur quelconque. Vous pouvez consulter un exemple ici.

Actuellement, Netra ne dispose pas de possibilitĂ© d'injection automatique du sidecar dans les services, mais des plans pour sa mise en Ɠuvre sont en cours.

L'avenir de Netramesh

L'objectif principal Netramesh est d'atteindre des coûts minimaux en ressources et de fournir des performances élevées, en offrant des fonctionnalités clés pour l'observabilité et le contrÎle des interactions interservices.

À l'avenir, Netramesh prendra en charge d'autres protocoles de niveau application en plus de HTTP. Bientît, une fonction de routage L7 sera disponible.

Utilisez Netramesh si vous ĂȘtes confrontĂ© Ă  des problĂšmes similaires, et Ă©crivez-nous vos questions et suggestions.

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