Tôt le matin du 19 mai (HAE), quay.io s'est écrasé. La catastrophe a affecté à la fois les consommateurs de quay.io et les projets Open Source utilisant quay.io comme plate-forme de création et de distribution de logiciels. Red Hat valorise la confiance des deux.
L'équipe d'ingénieurs SRE est immédiatement intervenue et a tenté de stabiliser le service Quay au plus vite. Cependant, pendant qu'ils faisaient cela, les clients ont perdu la capacité de pousser de nouvelles images, et ce n'est qu'occasionnellement qu'ils ont pu extraire les images existantes. Pour une raison inconnue, la base de données quay.io a été verrouillée après la mise à l'échelle du service à pleine capacité.
« Qu'est-ce qui a changé? "- c'est la première question qui est généralement posée dans de tels cas. Nous avons remarqué que peu de temps avant le problème, le cluster OpenShift Dedicated (sur lequel quay.io est en cours d'exécution) a commencé à se mettre à jour vers la version 4.3.19. Étant donné que quay.io est alimenté par Red Hat OpenShift Dedicated (OSD), les mises à jour régulières étaient courantes et n'ont jamais causé de problèmes. De plus, au cours des six derniers mois, nous avons procédé à plusieurs mises à niveau des clusters Quay sans interruption de service.
Pendant que nous essayions 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 tout déployer dessus en cas de besoin.
Analyse de la cause originelle
Le principal symptôme du crash était une avalanche de dizaines de milliers de connexions de base de données qui ont rendu l'instance MySQL effectivement désactivée. Cela a rendu difficile le diagnostic du problème. Nous avons fixé une limite au nombre maximum de connexions des clients pour aider l'équipe SRE à évaluer le problème. Nous n'avons pas remarqué de trafic inhabituel vers la base de données: en fait, la plupart des demandes concernaient des lectures, et quelques-unes seulement des écritures.
Nous avons également essayé d'identifier un modèle dans le trafic de la base de données qui pourrait provoquer cette avalanche. Cependant, il n'a pas été possible de trouver des modèles dans les journaux. En attendant que le nouveau cluster avec OSD 4.3.18 soit prêt, nous avons continué à essayer de lancer les pods quay.io. Chaque fois que le cluster atteignait sa pleine capacité, la base de données se figeait. Cela signifiait qu'il était nécessaire de redémarrer l'instance RDS en plus de tous les pods quay.io.
Le soir venu, nous avons stabilisé le service en lecture seule et désactivé le maximum de fonctions non essentielles (par exemple, garbage collection dans l'espace de noms) afin de réduire la charge sur la base de données. Le blocage s'est arrêté, mais la raison n'a jamais été trouvée . Le nouveau cluster OSD était prêt et nous avons migré le service, le trafic connecté et la surveillance continue.
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 verrous. Les ingénieurs d'OpenShift ont travaillé avec nous pour voir si les modifications apportées à Red Hat OpenShift 4.3.19 pouvaient avoir causé des problèmes de Quay. Cependant, rien n'a été trouvé et le problème n'a pas pu être reproduit en laboratoire .
Deuxième échec
Le 28 mai, peu avant midi HAE, quay.io s'est à nouveau écrasé avec le même symptôme: la base de données était bloquée. Encore une fois, nous avons mis toutes nos forces dans l'enquête. Tout d'abord, il était nécessaire de restaurer le service. Cependant , cette fois, le redémarrage du RDS et le redémarrage des pods quay.io n'ont abouti à rien : une nouvelle avalanche de connexions a balayé la base. Mais pourquoi?
Quay est écrit en Python et chaque pod fonctionne comme un seul conteneur monolithique. De nombreuses tâches parallèles s'exécutent simultanément dans l'environnement d'exécution du conteneur. Nous utilisons une bibliothèque
gevent
sousgunicorn
pour traiter les demandes Web. Lorsque Quay reçoit une requête (via notre propre API, ou via l'API Docker), un worker gevent lui est affecté. En règle générale, ce travailleur doit communiquer avec la base de données. Après le premier échec, nous avons constaté que les nœuds de calcul gevent se connectaient à la base de données en utilisant les paramètres par défaut.
Compte tenu du nombre important de pods Quay et des milliers de requêtes entrantes par seconde, le grand nombre de connexions à la base de données pourrait théoriquement submerger l'instance MySQL. Grâce à la surveillance, on savait que Quay traite en moyenne 5 000 requêtes par seconde. Le nombre de connexions à la base de données était à peu près le même. 5 mille connexions avec une marge correspondent aux capacités de notre instance RDS (ce qui ne peut pas être dit sur des dizaines de milliers).Pour une raison quelconque, il y a eu des pics inattendus dans le nombre de connexions , mais nous n'avons remarqué aucune corrélation avec les demandes entrantes.
Cette fois, nous étions déterminés à trouver et à corriger la source du problème, pas seulement à redémarrer. Des modifications ont été apportées à la base de code Quay pour limiter le nombre de connexions à la base de données pour chaque worker gevent . Ce numéro est devenu un paramètre dans la configuration: il est devenu possible de le changer "à la volée" sans construire une nouvelle image de conteneur. Pour connaître le nombre de connexions à gérer, nous avons exécuté plusieurs tests avec un environnement intermédiaire définissant des valeurs différentes pour voir comment cela affecterait les scénarios de test de charge. En conséquence, il s'est avéré queQuay commence à générer 502 erreurs lorsque le nombre de connexions dépasse 10 Ko.
Nous avons immédiatement déployé cette nouvelle version en production et commencé à surveiller le calendrier de connexion à la base de données. Dans le passé, la base était bloquée après environ 20 minutes. Après 30 minutes sans problème, nous avions de l'espoir, et une heure plus tard, de la confiance. Nous avons rétabli le trafic vers la publication sur le site et commencé l'analyse post-mortem.
Ayant réussi à contourner le problème menant au blocage, nous n'avons pas découvert ses véritables causes . Il a été confirmé qu'il n'était lié à aucune modification d'OpenShift 4.3.19, comme la même chose s'est produite sur la version 4.3.18, qui fonctionnait auparavant avec Quay sans aucun problème.
Il y avait clairement autre chose qui se cachait dans le cluster.
Etude détaillée
Quay.io utilise les paramètres par défaut pour se connecter à la base de données depuis six ans sans aucun problème. Qu'est ce qui a changé? Il est clair que le trafic vers quay.io n'a cessé de croître tout ce temps. Dans notre cas, tout semblait avoir atteint un certain seuil, ce qui a servi de déclencheur à une avalanche de connexions. Nous avons continué à examiner les journaux de la base de données après le deuxième crash, mais n'avons trouvé aucun modèle ni aucune relation évidente.
Dans l'intervalle, l'équipe SRE a travaillé sur des améliorations de l'observabilité des requêtes de Quay et de la santé globale du service. De nouvelles métriques et tableaux de bord ont été déployés indiquant quelles parties de Quay sont les plus demandées par les clients.
Quay.io a bien fonctionné jusqu'au 9 juin. Dans la matinée (via EDT), nous avons à nouveau assisté à une augmentation significative du nombre de connexions à la base de données. Cette fois, il n'y a pas eu de temps d'arrêt , car le nouveau paramètre limitait leur nombre et ne permettait pas de dépasser la bande passante MySQL. Cependant, pendant environ une demi-heure, de nombreux utilisateurs ont remarqué que quay.io était lent. Nous avons rapidement collecté toutes les données possibles à l'aide des outils de surveillance ajoutés. Un modèle est soudainement apparu.
Juste avant le saut dans les connexions, un grand nombre de requêtes ont été envoyées à l'API App Registry... Le registre des applications est une fonctionnalité peu connue de quay.io. Il vous permet de stocker des éléments tels que des graphiques Helm et des conteneurs riches en métadonnées. La plupart des utilisateurs de quay.io n'utilisent pas cette fonctionnalité, mais Red Hat OpenShift l'utilise activement. OperatorHub dans OpenShift stocke tous les opérateurs dans le registre d'applications. Ces transporteurs constituent la base de l'écosystème de charge de travail OpenShift et du modèle d'exploitation centré sur les partenaires (dans le cadre des opérations du jour 2).
Chaque cluster OpenShift 4 utilise des opérateurs de l'OperatorHub intégré pour publier un catalogue d'opérateurs disponibles pour l'installation et fournir des mises à jour pour ceux déjà installés. Avec la popularité croissante d'OpenShift 4, le nombre de clusters dans le monde a augmenté. Chacun de ces clusters charge le contenu de l'opérateur pour exécuter l'OperatorHub intégré en utilisant le registre d'applications dans quay.io comme backend. À la recherche de la source du problème, nous avons manqué le fait qu'à mesure que la popularité d'OpenShift augmentait progressivement, la charge sur l'une des fonctions quay.io rarement utilisées augmentait également .
Nous avons analysé le trafic des demandes du registre des applications et examiné le code du registre. Immédiatement, des failles ont été révélées, en raison desquelles les requêtes à la base de données ont été formées de manière sous-optimale. Ils n'ont causé aucun problème sous une charge légère, mais lorsqu'ils ont augmenté, ils sont devenus une source de problèmes. Le registre des applications s'est avéré avoir deux points de terminaison problématiques qui ne répondaient pas bien à une augmentation de la charge: le premier donnait une liste de tous les packages du référentiel, le second renvoyait tous les objets blob d'un package.
Élimination des causes
Au cours de la semaine suivante, nous avons optimisé le code de l'App Registry lui-même et de son environnement. De toute évidence, les requêtes SQL inefficaces ont été retravaillées, les appels inutiles à la commande ont été éliminés
tar
(elle était exécutée à chaque fois qu'un objet blob était récupéré) et la mise en cache a été ajoutée dans la mesure du possible. Ensuite, nous avons effectué des tests de performances approfondis et comparé les performances du registre d'applications avant et après les modifications.
Les demandes d'API qui prenaient jusqu'à une demi-minute étaient désormais traitées en quelques millisecondes . Nous avons déployé les modifications de la production la semaine prochaine et quay.io est stable depuis. Pendant ce temps, il y a eu plusieurs pics de trafic au point de terminaison App Registry, mais les améliorations apportées ont évité les pannes de base de données.
Qu'avons-nous appris?
Il est clair que tout service essaie d'éviter les temps d'arrêt. Dans notre cas, nous pensons que les crashs récents ont contribué à améliorer quay.io. Pour nous-mêmes, nous avons tiré plusieurs leçons principales que nous souhaitons partager:
- Les données sur qui utilise votre service et comment ne sont pas superflues . Parce que Quay «a juste fonctionné», nous n'avons jamais eu à passer du temps à optimiser le trafic et à gérer la charge. Tout cela a créé un faux sentiment de sécurité que le service pouvait évoluer indéfiniment.
- , — . Quay , . , — , .
- Évaluez l'impact de chacune des fonctions de service . Les clients utilisaient rarement le registre des applications, ce n'était donc pas une priorité pour notre équipe. Lorsque certaines fonctionnalités du produit sont à peine utilisées, leurs bogues apparaissent rarement et les développeurs arrêtent de surveiller le code. Il est facile de devenir la proie de l'illusion que c'est ainsi que cela devrait être - jusqu'à ce que soudainement cette fonctionnalité soit au centre d'un incident massif.
Et après?
Le travail pour assurer la stabilité du service ne s'arrête jamais et nous l'améliorons constamment. Les volumes de trafic sur quay.io continuent de croître et nous reconnaissons que nous devons faire de notre mieux pour être à la hauteur de la confiance de nos clients. Par conséquent, nous travaillons actuellement sur les tâches suivantes:
- , RDS.
- RDS. . , ( ); .
- . , .
- firewall’ - (WAF), , quay.io.
- , Red Hat OpenShift App Registry (Operator Catalogs), , quay.io.
- La prise en charge des spécifications d'artefacts Open Container Initiative (OCI) pourrait remplacer à long terme le registre d'applications. Il est actuellement mis en œuvre en tant que 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 de l'investissement continu de Red Hat dans quay.io alors que nous passons d'une petite équipe de type startup à une plate-forme mature dirigée par SRE. Nous savons que beaucoup de nos clients comptent sur quay.io pour leur travail quotidien (Red Hat inclus!) Et essayons d'être aussi ouverts que possible sur les perturbations récentes et les efforts continus d'amélioration.
PS du traducteur
Lisez aussi sur notre blog: