Post Mortem sur l'indisponibilité de Quay.io

Note de traduction.: au début du mois d'août, Red Hat a publiquement annoncé des solutions aux problèmes d'accessibilité rencontrés par les utilisateurs de son service au cours des mois précédents Quay.io (à la base — un registre pour les images de conteneurs, acquis par la société avec l'achat de CoreOS). Peu importe votre intérêt pour ce service en lui-même, le parcours des ingénieurs SRE de l'entreprise pour diagnostiquer et résoudre les causes de l'incident est instructif.

Post Mortem sur l'indisponibilité de Quay.io

Le 19 mai, tôt le matin (heure d'été de l'Est nord-américain, EDT), le service quay.io est tombé. L'incident a affecté à la fois les utilisateurs de quay.io et les projets Open Source utilisant quay.io comme plateforme pour construire et distribuer des logiciels. Red Hat tient à la confiance des deux groupes.

L'équipe des ingénieurs SRE s'est immédiatement mise au travail pour stabiliser le fonctionnement du service Quay. Cependant, pendant qu'ils s'occupaient de cela, les clients ont perdu la capacité de pousser de nouvelles images, ne réussissant qu'à récupérer sporadiquement celles existantes. Pour une raison inconnue, la base de données de quay.io se bloquait après l'extension du service à pleine capacité.

«Qu'est-ce qui a changé ?» — c'est la première question que l'on pose généralement dans de tels cas. Nous avons remarqué qu'un peu avant le problème, le cluster OpenShift Dedicated (sur lequel repose quay.io) avait commencé à se mettre à jour vers la version 4.3.19. Étant donné que quay.io fonctionne sur Red Hat OpenShift Dedicated (OSD), les mises à jour régulières étaient une opération routine et n'avaient jamais entraîné de problèmes. De plus, au cours des six derniers mois, nous avons mis à jour plusieurs fois les clusters Quay sans aucune interruption du service.

Alors que nous tentions de restaurer le service, d'autres ingénieurs ont commencé à préparer un nouveau cluster OSD avec la version précédente du logiciel, afin de pouvoir tout déployer dessus en cas de besoin.

Analyse des causes profondes

Le principal symptôme de la panne était une avalanche de dizaines de milliers de connexions à la base de données, rendant l'instance MySQL quasiment inutilisable. Cela compliquait le diagnostic du problème. Nous avons imposé une limite au nombre maximal de connexions des clients pour aider l'équipe SRE à évaluer le problème. Aucun trafic anormal vers la base de données n'a été observé : en réalité, la plupart des requêtes étaient des lectures, et seules quelques-unes étaient des écritures.

Nous avons également essayé d'identifier un modèle dans le trafic de la base de données qui aurait pu déclencher cette avalanche. Cependant, aucune règle n'a pu être trouvée dans les journaux. En attendant la disponibilité du nouveau cluster avec OSD 4.3.18, nous avons poursuivi nos tentatives de démarrage des pods quay.io. Chaque fois que le cluster atteignait sa pleine capacité, la base de données se bloquait. Cela signifiait qu'il était nécessaire de redémarrer l'instance RDS en plus de tous les pods quay.io.

Dans la soirée, nous avons stabilisé le service en mode lecture seule et désactivé le maximum de fonctionnalités non essentielles (comme la collecte des déchets dans l'espace de noms) pour réduire la charge sur la base de données. Les blocages ont cessé, mais la cause n'a pas été trouvée. Le nouveau cluster OSD était prêt, nous avons déplacé le service, connecté le trafic et continué à surveiller.

Quay.io fonctionnait de manière stable sur le nouveau cluster OSD, nous sommes donc retournés aux journaux de la base de données, mais nous n'avons pas pu trouver de corrélation expliquant les blocages. Les ingénieurs OpenShift ont travaillé avec nous pour essayer de comprendre si des changements dans Red Hat OpenShift 4.3.19 avaient pu causer des problèmes avec Quay. Cependant, rien n'a été découvert, et nous n'avons pas pu reproduire le problème en conditions de laboratoire..

Le deuxième incident

le 28 mai, peu avant midi EDT, quay.io est tombé à nouveau avec les mêmes symptômes : le fonctionnement de la base de données était bloqué. Et encore une fois, nous avons concentré tous nos efforts sur l'enquête. Tout d'abord, il fallait rétablir le fonctionnement du service. Cependant, cette fois, le redémarrage de RDS et le redémarrage des pods quay.io n'ont rien donné : une nouvelle avalanche de connexions a submergé la base de données. Mais pourquoi ?Quay est écrit en Python, et chaque pod fonctionne comme un conteneur monolithique unique. Un grand nombre de tâches parallèles sont exécutées simultanément dans l'environnement d'exécution du conteneur. Nous utilisons la bibliothèque

gevent pour traiter les requêtes web. Lorsque Quay reçoit une requête (via notre propre API ou via l'API de Docker), un travailleur gevent lui est assigné. Ce travailleur doit généralement se connecter à la base de données. Après la première panne, nous avons découvert que les travailleurs gevent se connectaient à la base de données en utilisant les paramètres par défaut. d'être gunicorn для обработки веб-запросов. Когда в Quay поступает запрос (через наш собственный API, или через API Docker’а), ему назначается gevent worker. Обычно этот worker должен связаться с базой данных. После первого сбоя мы обнаружили, что gevent worker’ы подключались к базе данных, используя настройки по умолчанию.

Compte tenu du nombre significatif de pod’ Quay et des milliers de requêtes reçues par seconde, un grand nombre de connexions à la base de données aurait théoriquement pu surcharger l'instance MySQL. Grâce à la surveillance, nous savions que Quay gérait en moyenne 5 000 requêtes par seconde. Environ le même chiffre était vrai pour le nombre de connexions à la base de données. 5 000 connexions étaient bien en deçà de la capacité de notre instance RDS (ce qui ne peut pas être dit pour des dizaines de milliers). Pour une raison quelconque, il y a eu des pics inattendus dans le nombre de connexions., cependant nous n'avons remarqué aucune corrélation avec les requêtes entrantes.

Cette fois, nous avons décidé de trouver et de résoudre la source du problème, au lieu de nous contenter d'un redémarrage. Des modifications ont été apportées à la base de code de Quay limitant le nombre de connexions à la base de données pour chaque worker gevent. Ce nombre est devenu un paramètre de configuration : il est devenu possible de le modifier « à la volée », sans avoir à reconstruire une nouvelle image de conteneur. Pour découvrir combien de connexions pouvaient réellement être gérées, plusieurs tests ont été effectués dans un environnement de staging, où différentes valeurs étaient spécifiées pour voir comment cela affectait les scénarios de tests de charge. Au final, il a été constaté que Quay commence à renvoyer des erreurs 502 lorsque le nombre de connexions dépasse 10 000.

Nous avons immédiatement déployé cette nouvelle version en production et avons commencé à surveiller le graphique des connexions à la base de données. Dans le passé, la base était bloquée environ 20 minutes. Après 30 minutes sans problème, nous avons commencé à avoir de l'espoir, et après une heure, nous avons eu la certitude. Nous avons restauré le trafic d'écriture sur le site et avons commencé l'analyse post-mortem.

Avoir réussi à contourner le problème causant le blocage, nous n'avons pas déterminé ses véritables causes.Il a été confirmé qu'il n'était pas lié à des modifications dans OpenShift 4.3.19, puisque le même phénomène avait eu lieu sur la version 4.3.18, qui avait auparavant fonctionné avec Quay sans aucun problème.

Il y avait clairement quelque chose de plus dans le cluster.

Une étude détaillée

Quay.io a utilisé les paramètres par défaut pour se connecter à la base de données sans aucun problème pendant six ans. Qu'est-ce qui a changé ? Il est clair que le trafic sur quay.io a augmenté de manière constante durant tout ce temps. Dans notre cas, il semblait que nous avions atteint un certain seuil qui a déclenché une avalanche de connexions. Nous avons continué à examiner les journaux de la base de données après la deuxième panne, mais nous n'avons trouvé aucune régularité ni relation évidente.

Pendant ce temps, l'équipe SRE travaillait sur des améliorations concernant l'observabilité des requêtes dans Quay et la santé globale du service. De nouvelles métriques et tableaux de bord, montrant quelles parties de Quay sont les plus sollicitées par les clients.

Quay.io a fonctionné normalement jusqu'au 9 juin. Le matin (heure de l'Est), nous avons de nouveau constaté une augmentation significative du nombre de connexions à la base de données. Cette fois-ci, il n'y a pas eu d'interruption, car un nouveau paramètre limitait leur nombre et empêchait de dépasser la capacité de MySQL. Cependant, pendant environ une demi-heure, de nombreux utilisateurs ont signalé un ralentissement de quay.io. Nous avons rapidement rassemblé toutes les données possibles, en utilisant les outils de surveillance ajoutés. Une régularité s'est soudainement manifestée.

Juste avant la montée en charge des connexions, un grand nombre de requêtes sont arrivées sur l'API App Registry. App Registry est une fonctionnalité peu connue de quay.io. Elle permet de stocker des éléments tels que des charts Helm et des conteneurs avec des métadonnées riches. La plupart des utilisateurs de quay.io n'utilisent pas cette fonction, mais elle est activement exploitée par Red Hat OpenShift. L'OperatorHub inclus dans OpenShift stocke tous les opérateurs dans App Registry. Ces opérateurs constituent la base de l'écosystème de charges de travail d'OpenShift et du modèle opérationnel (dans le cadre des opérations dites de « deuxième jour », Day 2), orienté vers les partenaires.

Chaque cluster OpenShift 4 utilise des opérateurs de l'OperatorHub intégré pour publier le catalogue des opérateurs disponibles pour installation et fournir des mises à jour pour ceux déjà installés. Avec la montée en popularité d'OpenShift 4, le nombre de clusters à travers le monde a également augmenté. Chacun de ces clusters télécharge le contenu des opérateurs pour lancer l'OperatorHub intégré, en utilisant l'App Registry à l'intérieur de quay.io comme backend. Dans notre recherche de la source du problème, nous avons négligé que, avec la popularité croissante d'OpenShift, la charge sur l'une des fonctionnalités rarement utilisées de quay.io augmentait également..

Nous avons effectué une analyse du trafic des requêtes de l'App Registry et examiné le code du registre. Des défauts ont immédiatement été découverts, entraînant des requêtes à la base de données sous-optimales. Sous une faible charge, elles ne posaient aucun problème, mais en augmentant, elles devenaient sources de soucis. L'App Registry avait deux points de terminaison problématiques qui réagissaient mal à l'augmentation de la charge : le premier fournissait une liste de tous les packages dans le dépôt, le second retournait tous les blobs pour un package.

Résolution des causes

La semaine suivante, nous nous sommes concentrés sur l'optimisation du code de l'App Registry et de son environnement. Des requêtes SQL manifestement inefficaces ont été retravaillées, des appels de commande superflus éliminés tar (ils étaient exécutés à chaque extraction de blobs), et un cache a été ajouté partout où c'était possible. Ensuite, des tests de performance à grande échelle ont été effectués pour comparer la vitesse de l'App Registry avant et après les modifications.

Les requêtes API, qui prenaient autrefois jusqu'à trente secondes, s'exécutent désormais en millisecondes.La semaine suivante, nous avons déployé les modifications en production, et depuis, quay.io fonctionne de manière stable. Pendant ce temps, plusieurs pics de trafic ont été observés sur le point de terminaison de l'App Registry, mais les améliorations apportées ont empêché toute interruption du fonctionnement de la base de données.

Qu'avons-nous appris ?

Il est clair que tout service cherche à éviter les temps d'arrêt. Dans notre cas, nous croyons que les pannes récentes ont contribué à améliorer quay.io. Nous avons retenu plusieurs leçons clés que nous souhaitons partager :

  1. Les données sur qui utilise votre service et comment ne sont jamais superflues.Comme Quay « fonctionnait simplement », nous n'avons jamais ressenti le besoin de consacrer du temps à l'optimisation du trafic et à la gestion de la charge. Tout cela a créé une fausse impression de sécurité, que le service pouvait se développer indéfiniment.
  2. Lorsque le service tombe, le rétablissement de son fonctionnement est la priorité principale.. Alors que Quay continuait de souffrir d'une base de données bloquée lors de la première panne, nos procédures standard n'avaient pas l'effet escompté et nous n'avons pas pu restaurer le service grâce à elles. Cela a conduit à une situation où nous avons dû passer du temps à analyser et rassembler des données dans l'espoir de trouver la cause profonde, au lieu de concentrer tous nos efforts sur la restauration des opérations.
  3. Évaluez l'impact de chaque fonctionnalité du service.. Les clients utilisaient rarement l'App Registry, ce qui ne le rendait pas prioritaire pour notre équipe. Lorsque certaines fonctionnalités du produit sont à peine utilisées, leurs bogues refont surface rarement, et les développeurs cessent de surveiller le code. Il est facile de tomber dans l'illusion que tout va bien, jusqu'à ce qu'une fonction se retrouve soudainement au centre d'un incident majeur.

Et après ?

Le travail sur la stabilité du service ne s'arrête jamais et nous l'améliorons constamment. Le volume de trafic sur quay.io continue de croître, et nous réalisons que nous devons faire tout ce qui est en notre pouvoir pour mériter la confiance de nos clients. C'est pourquoi nous travaillons actuellement sur les tâches suivantes :

  1. Déploiement de répliques de bases de données en lecture seule, pour aider le service à gérer le trafic correspondant en cas de problème avec l'instance principale de RDS.
  2. Mise à jour de l'instance de RDS. La version actuelle n'est pas, en soi, un problème. Plutôt, nous voulons simplement éliminer toute fausse piste (suivie lors de l'incident); maintenir le logiciel à jour permettra d'éliminer un facteur supplémentaire en cas de futures pannes.
  3. Mise en cache supplémentaire à travers le cluster. Nous continuons à rechercher des domaines où la mise en cache pourrait réduire la charge sur la base de données.
  4. Ajout d'un pare-feu d'applications Web (WAF), afin de voir qui se connecte à quay.io et pourquoi.
  5. À partir de la prochaine version, les clusters Red Hat OpenShift abandonneront l'App Registry au profit des catalogues d'opérateurs, basés sur des images de conteneurs disponibles sur quay.io.
  6. Une solution de remplacement à long terme de l'App Registry pourrait être la prise en charge des spécifications des artefacts de l'Open Container Initiative (OCI). Cela est actuellement mis en œuvre sous forme de fonctionnalité native de Quay et sera disponible pour les utilisateurs lorsque la spécification elle-même sera finalisée.

Tout ce qui précède fait partie des investissements continus de Red Hat dans quay.io alors que nous passons d'une petite équipe « esprit start-up » à une plateforme mature, gérée par des SRE. Nous savons que de nombreux clients comptent sur quay.io dans leur travail quotidien (y compris Red Hat !) et nous nous efforçons d'être aussi transparents que possible concernant les récents incidents et les efforts continus pour nous améliorer.

P.S. de l'auteur

Lisez aussi dans notre blog :

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