Disjoncteur Istio: déconnectez les conteneurs cassés

Les vacances sont terminées et nous revenons avec notre deuxième article de la série Istio Service Mesh.



Le sujet d'aujourd'hui est Circuit Breaker, qui, traduit en russe par électrotechnique, signifie «disjoncteur», familièrement - «disjoncteur». Ce n'est qu'à Istio que cette machine déconnecte non pas les circuits court-circuités ou surchargés, mais les conteneurs défectueux.

Comment cela devrait fonctionner idéalement


Lorsque les microservices sont gérés par Kubernetes, par exemple, dans le cadre de la plate-forme OpenShift, ils évoluent automatiquement vers le haut et vers le bas en fonction de la charge. Étant donné que les microservices fonctionnent dans des modules, il peut y avoir plusieurs instances de microservices conteneurisés à un point de terminaison, et Kubernetes acheminera les demandes et équilibrera la charge entre elles. Et - idéalement - tout cela devrait fonctionner parfaitement.

Nous nous souvenons que les microservices sont petits et éphémères. L'éphéméralité, qui signifie ici la simplicité d'émergence et de disparition, est souvent sous-estimée. La naissance et la mort de la prochaine instance de microservice dans pod sont très attendues, OpenShift et Kubernetes le font bien, et tout fonctionne très bien - mais encore une fois en théorie.

Comment ça marche vraiment


Imaginons maintenant qu'une instance particulière du microservice, c'est-à-dire le conteneur, soit devenue inutilisable: soit elle ne répond pas (erreur 503) ou, ce qui est plus désagréable, elle réagit, mais trop lentement. En d'autres termes, il coupe le son ou ne répond pas aux demandes, mais il ne le supprime pas automatiquement du pool. Que faut-il faire dans ce cas? Essayez encore? Le supprimer du schéma de routage? Et que signifie «trop lent» - combien est-ce en nombre et qui les détermine? Peut-être juste lui donner une pause et essayer plus tard? Si oui, combien plus tard?

Qu'est-ce que l'éjection de piscine à Istio


Et ici, Istio vient à la rescousse avec ses disjoncteurs, qui éliminent temporairement les conteneurs défectueux du pool de ressources de routage et d'équilibrage de charge, mettant en œuvre la procédure d'éjection du pool.

À l'aide d'une stratégie de détection des valeurs aberrantes, Istio détecte les courbes de pod qui sont éliminées de la ligne générale et les supprime du pool de ressources pendant un temps donné, appelé «fenêtre de sommeil».

Pour montrer comment cela fonctionne dans Kubernetes sur la plate-forme OpenShift, nous commençons par une capture d'écran des microservices fonctionnant normalement à partir de l'exemple dans le référentiel de démos de développeurs Red Hat . Ici, nous avons deux pods, v1 et v2, dans chacun desquels un conteneur fonctionne. Lorsque les règles de routage d'Istio ne sont pas utilisées, Kubernetes applique par défaut un routage à tour de rôle uniformément équilibré:


Se préparer pour un crash


Avant de procéder à l'éjection de pool, vous devez créer une règle de routage Istio. Supposons que nous voulons répartir les demandes entre les pods par rapport à 50/50. De plus, nous augmenterons le nombre de conteneurs v2 de un à deux, comme ceci:

oc scale deployment recommendation-v2 --replicas=2 -n tutorial 

Nous définissons maintenant une règle de routage pour que le trafic soit réparti entre les pods dans un rapport 50/50.


Et voici le résultat de cette règle:


Il est possible de se plaindre que sur cet écran ce n'est pas 50/50, mais 14: 9, mais avec le temps la situation s'améliorera.

Nous organisons un échec


Et maintenant, nous allons désactiver l'un des deux conteneurs v2 afin d'avoir un conteneur sain v1, un conteneur sain v2 et un conteneur défectueux v2:


Résoudre le crash


Nous avons donc un conteneur défectueux, et il est temps pour Pool Ejection. En utilisant une configuration très simple, nous exclurons ce conteneur défaillant de tout schéma de routage pendant 15 secondes dans l'espoir qu'il reviendra à un état sain (soit il redémarrera, soit il restaurera les performances). Voici à quoi ressemble cette config et les résultats de son travail:



Comme vous pouvez le voir, le conteneur défectueux v2 n'est plus utilisé lors du routage des demandes, car il a été supprimé du pool. Mais après 15 secondes, il retournera automatiquement à la piscine. En fait, nous venons de montrer comment fonctionne Pool Ejection.

Commencez à construire l'architecture


Pool Ejection, combiné aux capacités de surveillance d'Istio, vous permet de commencer à créer un cadre pour remplacer automatiquement les conteneurs défectueux afin de réduire, voire d'éliminer les temps d'arrêt et les plantages.

La NASA a une devise de haut niveau - l'échec n'est pas une option, écrit par le directeur de vol Gene Krantz . Il peut être traduit en russe par «la défaite n'est pas une option», et le fait est que tout peut être fait pour fonctionner avec suffisamment de volonté. Cependant, dans la vraie vie, les échecs ne se produisent pas simplement, ils sont inévitables, partout et en tout. Et comment y faire face dans le cas des microservices? À notre avis, il vaut mieux ne pas compter sur la volonté, mais sur les capacités des conteneurs, Kubernetes , Red Hat OpenShift et Istio .

Istio, comme nous l'avons écrit ci-dessus, met en œuvre le concept de disjoncteurs, qui a fait ses preuves dans le monde physique. Et tout comme une machine automatique déconnecte une partie problématique d'un circuit, le logiciel Circuit Breaker dans Istio déconnecte la connexion entre le flux de demandes et le conteneur de problèmes lorsque quelque chose ne va pas avec le point de terminaison, par exemple, lorsque le serveur tombe en panne ou commence à ralentir.

De plus, dans le deuxième cas, il n'y a que plus de problèmes, car les freins d'un conteneur non seulement provoquent une cascade de retards dans les services qui y accèdent et, par conséquent, réduisent les performances du système dans son ensemble, mais provoquent également des demandes répétées au service déjà lent, ce qui ne fait qu'exacerber la situation. .

Disjoncteur en théorie


Le disjoncteur est un proxy qui contrôle le flux des demandes vers le point de terminaison. Lorsque ce point cesse de fonctionner ou, selon les paramètres, il commence à ralentir, le proxy se déconnecte du conteneur. Le trafic est ensuite redirigé vers d'autres conteneurs, juste à cause de l'équilibrage de charge. La connexion reste ouverte (ouverte) pendant une fenêtre de sommeil donnée, disons deux minutes, puis est considérée comme semi-ouverte (semi-ouverte). Tenter d'envoyer la demande suivante détermine l'état de communication supplémentaire. Si tout va bien avec le service, la connexion revient à l'état opérationnel et se ferme à nouveau. S'il y a toujours un problème avec le service, la connexion s'ouvre et la fenêtre de veille est réactivée. Voici à quoi ressemble le diagramme d'état simplifié du disjoncteur:


Il est important de noter ici que tout cela se passe au niveau, pour ainsi dire, de l'architecture système. Par conséquent, à un moment donné, vous devrez apprendre à vos applications à travailler avec le disjoncteur, par exemple, fournir une valeur par défaut en réponse ou, si possible, ignorer l'existence du service. Un modèle de cloison est utilisé pour cela, mais il dépasse le cadre de cet article.

Disjoncteur en pratique


Par exemple, nous lancerons sur OpenShift deux versions de notre microservice de recommandations. La version 1 fonctionnera bien, mais dans la v2, nous intégrerons un délai pour simuler les freins sur le serveur. Pour afficher les résultats, utilisez l'outil de siège :

 siege -r 2 -c 20 -v customer-tutorial.$(minishift ip).nip.io 


Tout semble fonctionner, mais à quel prix? À première vue, nous avons une disponibilité à 100%, mais regardons de plus près - la durée maximale des transactions peut atteindre 12 secondes. Il s'agit clairement d'un goulot d'étranglement et doit être brodé.

Pour ce faire, nous utiliserons Istio pour éliminer l'accès aux conteneurs lents. Voici à quoi ressemble la configuration correspondante en utilisant le disjoncteur:


La dernière ligne avec le paramètre httpMaxRequestsPerConnection signale que la connexion avec doit s'ouvrir lorsque vous essayez de créer une connexion de plus - la seconde - en plus de la connexion existante. Étant donné que notre conteneur imite un service de freinage, de telles situations se produisent périodiquement, puis Istio retournera une erreur 503, et voici ce que le siège montrera:


OK, nous avons un disjoncteur, quelle est la prochaine étape?


Nous avons donc implémenté un arrêt automatique, sans toucher au code source des services eux-mêmes. En utilisant le disjoncteur et la procédure d'éjection de piscine décrits ci-dessus, nous pouvons retirer les conteneurs de frein du pool de ressources jusqu'à ce qu'ils reviennent à la normale et vérifier leur état à une fréquence donnée - dans notre exemple, cela fait deux minutes (paramètre sleepWindow).

Veuillez noter que la capacité de l'application à répondre à l'erreur 503 est toujours définie au niveau de son code source. Il existe de nombreuses stratégies pour travailler avec un disjoncteur, qui sont appliquées en fonction de la situation.

Dans le prochain article: nous parlerons du traçage et de la surveillance, qui sont déjà intégrés ou facilement ajoutés à Istio, ainsi que de la manière d'introduire intentionnellement des erreurs dans le système.

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


All Articles