Suivi et surveillance d'Istio: microservices et principe d'incertitude

Le principe d'incertitude de Heisenberg stipule qu'il est impossible de mesurer simultanément la position d'un objet et sa vitesse. Si un objet se déplace, il n'a alors aucun emplacement. Et si l'emplacement est, cela signifie qu'il n'a pas de vitesse.



Quant aux microservices sur la plate-forme Red Hat OpenShift (et exécutant Kubernetes), grâce au logiciel open source correspondant, ils peuvent signaler simultanément leurs performances et leur santé. Bien sûr, cela ne réfute pas l'ancien Heisenberg, mais cela élimine l'incertitude lorsque vous travaillez avec des applications cloud. Istio facilite l'organisation du suivi (traçage) et de la surveillance de ces applications pour tout garder sous contrôle.

Définir la terminologie


Par traçage, nous entendons l'activité du système de journalisation. Cela semble assez général, mais en fait l'une des règles principales ici est de vider les données de trace dans le stockage approprié sans se soucier de les formater. Et tout le travail de recherche et d'analyse des données est confié à leur consommateur. Istio utilise le système de trace Jaeger, qui implémente le modèle de données OpenTracing.

Par traces (Traces, et le mot «traces» est utilisé ici dans le sens de «traces», comme, par exemple, dans un examen balistique), nous entendrons des données qui décrivent complètement le passage d'une demande ou d'une unité de travail, comme on dit, «de et vers». Par exemple, tout ce qui se passe entre le moment où l'utilisateur appuie sur un bouton d'une page Web et le moment où les données sont renvoyées, y compris tous les microservices impliqués. On peut dire qu'une trace décrit (ou simule) complètement le passage de la requête dans les deux sens. Dans l'interface Jaeger, les pistes sont décomposées en composants le long de l'axe du temps, comme la façon dont une chaîne peut être décomposée en maillons séparés. Ce n'est qu'au lieu de liens que la piste se compose de ce qu'on appelle des travées.

La durée est l'intervalle entre le début d'une unité d'oeuvre et son achèvement. Poursuivant l'analogie, nous pouvons dire que chaque travée est un maillon distinct de la chaîne. Une travée peut ou non avoir une ou plusieurs travées enfants. Par conséquent, la plage de niveau supérieur (plage racine) aura la même durée totale que la trace à laquelle elle appartient.

La surveillance est, en fait, l'observation même de votre système - à travers les yeux, via une interface utilisateur ou au moyen de l'automatisation. La surveillance est basée sur des données de trace. Dans Istio, la surveillance est implémentée à l'aide des outils Prometheus et possède une interface utilisateur correspondante. Prometheus prend en charge la surveillance automatique à l'aide des alertes Alertes et Alert Managers.

Laissez les pseudos


Pour que le traçage soit possible, l'application doit créer une collection de plages. Ils doivent ensuite être exportés vers Jaeger, afin qu'il crée à son tour une représentation visuelle de la trace. Entre autres choses, ces plages marquent le nom de l'opération, ainsi que les horodatages de son début et de sa fin. Les étendues sont envoyées en transmettant les en-têtes de requête HTTP spécifiques à Jaeger des requêtes entrantes aux requêtes sortantes. Selon le langage de programmation utilisé, cela peut nécessiter une légère modification du code source de l'application. Voici un exemple de code Java (lors de l'utilisation du framework Spring Boot) qui ajoute des en-têtes B3 (style Zipkin) à votre demande dans la classe de configuration Spring:


Les paramètres d'en-tête suivants sont utilisés:


Si vous utilisez Java, vous pouvez laisser le code intact, ajoutez simplement quelques lignes au fichier Maven POM et définissez les variables d'environnement. Voici les lignes que vous devez ajouter au fichier POM.XML pour implémenter le résolveur Jaeger Tracer:


Et les variables d'environnement correspondantes sont définies dans le Dockerfile:


C'est tout, maintenant tout est configuré, et nos microservices vont commencer à générer des données de trace.

Nous regardons en termes généraux


Istio comprend un panneau de contrôle simple basé sur Grafana. Lorsque tout est configuré et exécuté sur la plate-forme Red Hat OpenShift PaaS (dans notre exemple, Red Hat OpenShift et Kubernetes sont déployés sur minishift), ce panneau est lancé avec la commande suivante:

open "$(minishift openshift service grafana -u)/d/1/istio-dashboard?refresh=5⩝Id=1" 

Le panneau Grafana vous permet d'évaluer rapidement le système. Un fragment de ce panneau est illustré dans la figure ci-dessous:


Ici, vous pouvez voir que le client de microservice appelle la préférence de microservice v1 et que, à son tour, il appelle les recommandations de microservices v1 et v2. Le panneau Grafana possède un bloc de lignes de tableau de bord pour les mesures de haut niveau, telles que le nombre total de demandes (volume de demandes global), le pourcentage de demandes réussies (taux de réussite), les erreurs 4xx. En outre, il existe une vue de maillage de serveur avec des graphiques pour chaque service et un bloc de ligne de services pour afficher des informations détaillées pour chaque conteneur pour chaque service.

Maintenant, creusez plus profondément


Avec une trace correctement configurée, Istio, comme on dit, dès la sortie de la boîte vous permet de vous plonger dans l'analyse des performances du système. Dans l'interface utilisateur de Jaeger, vous pouvez afficher les traces et voir jusqu'où elles vont et où elles vont, ainsi que localiser visuellement les goulots d'étranglement des performances. Lorsque vous utilisez Red Hat OpenShift sur la plate-forme minishift, lancez Jaeger UI à l'aide de la commande suivante:

 minishift openshift service jaeger-query --in-browser 


Que peut-on dire de la trace sur cet écran:

  • Il est divisé en 7 travées.
  • Le temps d'exécution total est de 6,99 ms.
  • La recommandation de microservice, qui est la dernière de la chaîne, prend 0,69 ms.

Les diagrammes de ce type vous permettent de déterminer rapidement une situation où les performances de l'ensemble du système souffrent en raison d'un seul service qui fonctionne mal.

Compliquons maintenant la tâche et lançons deux instances du microservice de recommandation: v2 avec la commande oc scale --replicas = 2 deployment / recommendation-v2. Voici les pods que nous aurons après cela:


Si nous revenons maintenant à Jaeger et déployons l'intervalle pour le service de recommandation, nous verrons vers quelles demandes de pod sont acheminées. Ainsi, nous pouvons facilement localiser les freins au niveau du pod spécifique. Vous devriez regarder le champ node_id:


Où et comment tout se passe


Maintenant, nous allons à l'interface Prometheus et, comme on pouvait s'y attendre, nous voyons là que les demandes entre les deuxième et première versions du service de recommandation sont divisées dans un rapport 2: 1, strictement par le nombre de pods de travail. De plus, ce graphique changera dynamiquement lors de la montée et de la descente des pods, ce qui sera particulièrement utile avec Canary Deployment (nous examinerons ce schéma de déploiement plus en détail la prochaine fois).


Ce n'est qu'un début


En fait, aujourd'hui, comme on dit, nous n'avons touché que légèrement à une mine d'informations utiles sur Jaeger, Grafana et Prometheus. En général, c'était notre objectif - vous guider dans la bonne direction et ouvrir les perspectives d'Istio.

Et rappelez-vous, tout cela est déjà intégré à Istio. Lorsque vous utilisez certains langages de programmation (par exemple, Java) et frameworks (par exemple, Spring Boot), tout cela peut être réalisé sans toucher complètement au code d'application lui-même. Oui, le code devra être légèrement modifié si vous utilisez d'autres langages, principalement Nodejs ou C #. Mais comme la traçabilité (lire, «traçage») est l'une des conditions préalables à la création de systèmes cloud fiables, dans tous les cas, vous devrez modifier le code, que vous ayez Istio ou non. Alors pourquoi ne pas dépenser l'effort de manière plus rentable?

Au moins afin de toujours répondre aux questions «où?» Et «à quelle vitesse?» Avec 100% de certitude.

L'ingénierie du chaos à Istio: elle a été conçue


La capacité de casser des choses aide à s'assurer qu'elles ne cassent pas


Les tests de logiciels sont non seulement une chose compliquée, mais aussi une chose importante. Dans le même temps, tester l'exactitude (par exemple, si une fonction renvoie le résultat correct) est une chose, et tester dans un réseau peu fiable est une tâche complètement différente (on pense souvent que le réseau fonctionne toujours sans échecs, et c'est la première des huit idées fausses concernant la distribution informatique). L'une des difficultés pour résoudre ce problème est de savoir comment simuler les défaillances du système ou les introduire intentionnellement en effectuant ce que l'on appelle l'injection de défauts. Cela peut être fait en modifiant le code source de l'application elle-même. Mais vous ne testerez pas votre code d'origine, mais sa version, qui simule spécifiquement les échecs. En conséquence, vous courez le risque d'entrer dans une étreinte fatale d'injection de faute et d'entrer en collision avec les heisenbags - échecs qui disparaissent lorsque vous essayez de les détecter.

Et maintenant, nous allons montrer comment Istio aide à faire face à ces difficultés un à deux.

À quoi ça ressemble quand tout va bien


Considérez le scénario suivant: nous avons deux modules pour notre microservice de recommandation, que nous avons pris dans le didacticiel Istio. Un pod est marqué comme v1 et l'autre comme v2. Comme vous pouvez le voir, alors que tout fonctionne bien:


(Soit dit en passant, le numéro à droite n'est qu'un compteur d'appels pour chaque module)

Mais nous n'en avons pas besoin, n'est-ce pas? Eh bien, essayons de tout casser sans toucher du tout au code source.

Nous organisons des interruptions dans le travail du microservice


Vous trouverez ci-dessous le fichier yaml pour la règle de routage Istio, qui dans la moitié des cas échouera (erreur de serveur 503):


Veuillez noter que nous prescrivons explicitement que dans la moitié des cas, l'erreur 503 doit être renvoyée.

Et voici une capture d'écran de la commande curl lancée dans la boucle après avoir activé cette règle pour simuler les échecs. Comme vous pouvez le voir, la moitié des demandes renvoie l'erreur 503, et quel que soit le pod - v1 ou v2 - vers lequel elles vont:


Pour restaurer un fonctionnement normal, il suffit de supprimer cette règle, dans notre cas, la commande istioctl delete routerule recommendation-503 -n tutorial. Ici, Tutorial est le nom du projet Red Hat OpenShift qui exécute notre tutoriel Istio.

Faire des retards artificiels


Les erreurs artificielles 503 aident à tester la tolérance aux pannes du système, mais la capacité de prévoir et de gérer les retards devrait vous impressionner encore plus. Et les retards dans la vie réelle se produisent plus souvent que les échecs. Un microservice lent est le poison dont souffre tout le système. Grâce à Istio, vous pouvez tester le code lié au retard de traitement sans le changer du tout. Pour commencer, nous montrerons comment procéder dans le cas de retards de réseau introduits artificiellement.

Veuillez noter qu'après de tels tests, vous devrez peut-être (ou souhaiter) affiner votre code. La bonne nouvelle est que dans ce cas, vous agirez de manière proactive et non réactive. C'est ainsi que le cycle de développement doit être construit: coding-testing-feedback-coding-testing ...

Voilà à quoi ressemble la règle ... Bien que vous sachiez quoi? Istio est si simple, et ce fichier yaml est si clair que tout dans cet exemple parle de lui-même, jetez un œil:


Dans la moitié des cas, nous aurons un délai de 7 secondes. Et ce n'est pas du tout la même chose que si nous insérions la commande sleep dans le code source, car Istio retarde vraiment la requête de 7 secondes. Comme Istio prend en charge le traçage Jaeger, ce délai est excellent dans l'interface utilisateur biaisée de Jaeger, comme illustré dans la capture d'écran ci-dessous. Faites attention à la longue demande dans le coin supérieur droit du diagramme - sa durée est de 7,02 secondes:


Ce scénario vous permet de tester le code dans des conditions de latence du réseau. Et il est clair qu'en supprimant cette règle, nous supprimerons le retard artificiel. Nous répétons, mais encore une fois, nous avons fait tout cela sans toucher au code source.

Ne recule pas et n'abandonne pas


Une autre caractéristique d'Istio qui est utile pour l'ingénierie du chaos est les appels répétés au service un nombre spécifié de fois. Le point ici n'est pas d'arrêter d'essayer, lorsque la première demande se termine avec l'erreur 503 - et puis, peut-être, pour la onzième fois, nous avons de la chance. Peut-être que le service se fixe pour une courte période pour une raison ou une autre. Oui, cette raison doit être découverte et éliminée. Mais c'est plus tard, mais pour l'instant essayons de faire fonctionner le système.

Donc, nous voulons que le service donne une erreur 503 de temps en temps, et après cela, Istio essaiera de le contacter à nouveau. Et ici, nous avons clairement besoin d'un moyen de générer l'erreur 503, sans toucher au code lui-même ...

Arrêtez d'attendre! Nous venons de le faire.

Ce fichier fera que le service recommendation-v2 générera une erreur 503 dans la moitié des cas:


De toute évidence, une partie des demandes échouera:


Et maintenant, nous allons utiliser la fonction Réessayer Istio:


Cette règle de routage effectue trois tentatives avec un intervalle de deux secondes et devrait réduire (et idéalement supprimer complètement du radar) les erreurs 503:


Nous résumons: nous avons fait en sorte qu'Istio, dans un premier temps, génère une erreur 503 pour la moitié des demandes. Et deuxièmement, le même Istio fait trois tentatives pour se reconnecter au service si une erreur 503 se produit. Par conséquent, tout fonctionne très bien. Ainsi, en utilisant la fonction Réessayer, nous avons tenu notre promesse de ne pas reculer et de ne pas abandonner.

Et oui, nous l'avons fait à nouveau sans toucher du tout au code. Tout ce dont nous avions besoin, c'était de deux règles de routage Istio:


Comment ne pas laisser tomber un utilisateur ou sept n'attendez pas


Et maintenant, nous retournons la situation et considérons le scénario lorsque vous n'avez pas à battre en retraite et à ne renoncer qu'à un certain temps. Et puis il vous suffit d'arrêter d'essayer de traiter la demande afin de ne pas forcer tout le monde à attendre un service de freinage. En d'autres termes, nous ne protégerons pas la position perdue, mais nous passerons à la ligne de réserve afin de ne pas laisser tomber l'utilisateur du site et ne pas le forcer à languir dans l'ignorance.

Dans Istio, vous pouvez définir le délai d'expiration de la demande. Si le service dépasse ce délai d'expiration, l'erreur 504 (délai d'expiration de la passerelle) est renvoyée - encore une fois, tout cela se fait via la configuration Istio. Mais nous devrons ajouter la commande sleep au code source du service (puis, bien sûr, exécuter la reconstruction et le redéploiement) pour simuler le lent fonctionnement du service. Hélas, cela ne fonctionnera pas autrement.

Donc, nous avons inséré un sommeil de trois secondes dans le code de service de recommandation v2, reconstruit l'image correspondante et fait un re-mode de conteneur, et maintenant nous allons ajouter un délai d'expiration en utilisant la règle de routage Istio suivante:


La capture d'écran ci-dessus montre que nous essayons de contacter le service de recommandation si nous ne recevons pas de réponse dans la seconde, c'est-à-dire avant que l'erreur 504 ne se produise. Après avoir appliqué cette règle de routage (et ajouté une mise en veille de trois secondes au code du service de recommandation : v2), nous obtenons ceci:


Nous répétons à nouveau, mais le délai peut être défini sans toucher au code source. Et le bonus supplémentaire ici est que vous pouvez maintenant modifier votre code afin qu'il réponde à un délai d'attente, et il est facile de tester ces améliorations en utilisant Istio.

Et maintenant tous ensemble


Faire un peu de chaos avec Istio est un excellent moyen de tester votre code et la fiabilité de votre système dans son ensemble. Les modèles de repli, de cloison et de disjoncteur, les mécanismes de création de défaillances et de retards artificiels, ainsi que les appels et les délais d'expiration répétés seront très utiles lors de la création de systèmes cloud tolérants aux pannes. Combinés à Kubernetes et Red Hat OpenShift, ces outils vous aident à affronter l'avenir avec confiance.

Source: https://habr.com/ru/post/fr485136/


All Articles