Post Mortem zur Erreichbarkeit von Quay.io

Anmerkung des Übersetzers.: Anfang August hat Red Hat öffentlich über die Lösungen für die Verfügbarkeitsprobleme berichtet, die in den Monaten zuvor bei den Nutzern ihres Dienstes aufgetreten sind. Quay.io (basierend auf einem Container-Image-Registry, das das Unternehmen mit dem Kauf von CoreOS übernommen hat). Unabhängig von Ihrem Interesse an diesem Dienst ist der Weg, den die SRE-Ingenieure des Unternehmens zur Diagnose und Behebung der Ursachen des Ausfalls gegangen sind, lehrreich.

Post Mortem zur Erreichbarkeit von Quay.io

Am 19. Mai, früh am Morgen (nach nordamerikanischer Sommerzeit, EDT), ist der Dienst quay.io ausgefallen. Der Ausfall betraf sowohl die Nutzer von quay.io als auch Open-Source-Projekte, die quay.io als Plattform für den Bau und die Verbreitung von Software verwenden. Red Hat legt großen Wert auf das Vertrauen beider Gruppen.

Das Team der SRE-Ingenieure setzte sofort alles daran, den Service Quay so schnell wie möglich wieder stabil zu machen. Während sie daran arbeiteten, konnten die Kunden jedoch keine neuen Images pushen und nur sporadisch bestehende pullen. Aus unbekannten Gründen wurde die Datenbank von quay.io nach der Skalierung des Dienstes auf volle Leistung blockiert.

«Was hat sich geändert?» — das ist die erste Frage, die in solchen Fällen gestellt wird. Wir haben festgestellt, dass kurz vor dem Problem der OpenShift Dedicated-Cluster (auf dem quay.io läuft) mit dem Update auf Version 4.3.19 begann. Da quay.io auf Red Hat OpenShift Dedicated (OSD) läuft, waren regelmäßige Updates eine alltägliche Operation und führten nie zu Problemen. Darüber hinaus haben wir in den vergangenen sechs Monaten mehrere Cluster-Updates bei Quay durchgeführt, ohne dass es zu Wartungsunterbrechungen kam.

Während wir versuchten, den Dienst wiederherzustellen, begannen andere Ingenieure mit der Vorbereitung eines neuen OSD-Clusters mit der vorherigen Softwareversion, um im Ernstfall alles darauf zu implementieren.

Ursachenanalyse

Das Hauptsymptom des Ausfalls war eine Welle von zehntausenden Verbindungen zur Datenbank, wodurch die MySQL-Instanz faktisch nicht mehr funktionsfähig war. Dies erschwerte die Diagnose des Problems. Wir haben die maximale Anzahl von Verbindungen von Clients begrenzt, um dem SRE-Team zu helfen, das Problem zu bewerten. Es wurde kein ungewöhnlicher Datenverkehr zur Datenbank festgestellt: Tatsächlich waren die meisten Anfragen Leseanfragen, und nur wenige waren Schreibanfragen.

Wir haben auch versucht, ein Muster im DB-Verkehr zu finden, das diese Welle auslösen könnte. Allerdings konnten im Log keine Muster entdeckt werden. In der Erwartung, dass der neue Cluster mit OSD 4.3.18 bereit ist, versuchten wir weiterhin, die Pods von quay.io zu starten. Jedes Mal, wenn der Cluster seine volle Kapazität erreichte, hing die Datenbank. Das bedeutete, dass wir zusätzlich zu allen Pods von quay.io die RDS-Instanz neu starten mussten.

Bis zum Abend stabilisierten wir den Dienst im Nur-Lesen-Modus und schalteten möglichst viele unwesentlichen Funktionen (wie das Aufräumen im Namensraum) ab, um die Belastung der Datenbank zu verringern. Die Hänger hörten auf, aber der Grund wurde nicht gefunden. Der neue OSD-Cluster war bereit, und wir migrierten den Dienst, schlossen den Verkehr an und setzten die Überwachung fort.

Quay.io lief stabil auf dem neuen OSD-Cluster, also haben wir die Datenbank-Logs wieder überprüft, konnten aber keine Korrelation finden, die die Sperrungen erklärte. Die Ingenieure von OpenShift arbeiteten mit uns zusammen, um zu verstehen, ob Änderungen in Red Hat OpenShift 4.3.19 Probleme mit Quay verursacht haben könnten. Doch es wurde nichts festgestellt und es war nicht möglich, das Problem im Labor zu reproduzieren.

Der zweite Ausfall

Am 28. Mai, kurz vor Mittag EDT, fiel quay.io erneut mit demselben Symptom aus: die Funktion der Datenbank wurde blockiert. Und wieder versammelten wir alle Kräfte für die Untersuchung. Zuerst musste der Dienst wiederhergestellt werden. Allerdings führten diesmal der Neustart von RDS und der Neustart der Pods von quay.io zu nichts: eine weitere Welle von Verbindungen überkam die Datenbank. Aber warum?

Quay ist in Python geschrieben, und jeder Pod funktioniert als ein einziger monolithischer Container. Im Container-Execution-Umfeld werden gleichzeitig viele parallele Aufgaben ausgeführt. Wir verwenden die Bibliothek gevent unter gunicorn für die Verarbeitung von Webanfragen. Wenn Quay eine Anfrage erhält (über unsere eigene API oder über die Docker-API), wird ihm ein Gevent-Worker zugewiesen. Normalerweise muss dieser Worker mit der Datenbank kommunizieren. Nach dem ersten Ausfall stellten wir fest, dass die Gevent-Worker sich mit der Datenbank unter Verwendung der Standardeinstellungen verbunden hatten.

Angesichts der erheblichen Anzahl an Quay-Pods und Tausenden von Anfragen pro Sekunde könnte eine große Anzahl von Datenbankverbindungen theoretisch eine MySQL-Instanz überlasten. Die Überwachung hat gezeigt, dass Quay durchschnittlich 5.000 Anfragen pro Sekunde verarbeitet. Etwa gleich hoch war die Anzahl der Datenbankverbindungen. 5.000 Verbindungen lagen damit im Rahmen der Möglichkeiten unserer RDS-Instanz (im Gegensatz zu Zehntausenden). Aus irgendeinem Grund gab es unerwartete Spitzen bei der Anzahl der Verbindungen., aber wir bemerkten keine Korrelation mit den eingehenden Anfragen.

Diesmal haben wir uns entschieden, die Quelle des Problems zu finden und zu beheben, anstatt nur einen Neustart durchzuführen. In den Quellcode von Quay wurden Änderungen eingebracht, die die Anzahl der Datenbankverbindungen für jeden Worker gevent beschränken. Diese Anzahl wurde zu einem Parameter in der Konfiguration: Es war möglich, sie „on-the-fly“ zu ändern, ohne ein neues Container-Image erstellen zu müssen. Um herauszufinden, wie viele Verbindungen tatsächlich verarbeitet werden können, wurden mehrere Tests mit einer Staging-Umgebung durchgeführt, bei denen verschiedene Werte festgelegt wurden, um zu sehen, wie sich das auf die Lasttestszenarien auswirkt. Letztendlich stellte sich heraus, dass Quay beginnt, 502-Fehler auszugeben, wenn die Anzahl der Verbindungen 10.000 überschreitet.

Wir haben sofort diese neue Version in der Produktion bereitgestellt und die Verbindungsgrafik zur Datenbank überwacht. In der Vergangenheit war die Datenbank etwa 20 Minuten nach dem Start blockiert. Nach 30 problemlosen Minuten hatten wir Hoffnung, und nach einer Stunde hatten wir Gewissheit. Wir haben den Schreibtraffic auf der Website wiederhergestellt und mit der Post-Mortem-Analyse begonnen.

Indem wir das Problem, das zur Blockierung führte, umgingen, konnten wir die wahren Ursachen nicht klären.Es stellte sich heraus, dass es nicht mit Änderungen in OpenShift 4.3.19 zusammenhängt, da dasselbe auch in der Version 4.3.18 aufgetreten ist, die zuvor ohne Probleme mit Quay funktionierte.

Im Cluster verbarg sich offensichtlich etwas anderes.

Eine detaillierte Untersuchung

Quay.io hat sechs Jahre lang die Standardkonfiguration zur Verbindung mit der Datenbank ohne Probleme genutzt. Was hat sich geändert? Es ist klar, dass der Verkehr auf quay.io in dieser Zeit ständig zugenommen hat. In unserem Fall schien es, als ob ein gewisser Schwellenwert erreicht wurde, der einen Anstoß zu einer Flut von Verbindungen gab. Wir haben die Datenbankprotokolle nach dem zweiten Ausfall weiterhin untersucht, konnten jedoch keine Muster oder offensichtlichen Zusammenhänge feststellen.

Währenddessen hat das SRE-Team an Verbesserungen der Sichtbarkeit von Anfragen in Quay und der allgemeinen Gesundheit des Dienstes gearbeitet. Es wurden neue Metriken und Dashboards bereitgestellt, die zeigen, welche Teile von Quay bei den Kunden am meisten gefragt sind.

Quay.io funktionierte bis zum 9. Juni normal. Am Morgen (EDT) waren wir erneut Zeugen eines signifikanten Anstiegs der Verbindungen zur Datenbank. Diesmal gab es keine Ausfallzeiten, da ein neuer Parameter ihre Anzahl begrenzte und es nicht erlaubte, die Kapazität von MySQL zu überschreiten. Allerdings berichteten viele Nutzer etwa eine halbe Stunde lang von einer langsamen Leistung von quay.io. Wir haben schnell alle verfügbaren Daten gesammelt und die hinzugefügten Überwachungswerkzeuge genutzt. Plötzlich trat ein Muster zutage.

Vor dem Anstieg der Verbindungen gab es eine große Anzahl von Anfragen an die App Registry API. Die App Registry ist eine wenig bekannte Funktion von quay.io. Sie ermöglicht das Speichern von Dingen wie Helm-Charts und Containern mit reichhaltigen Metadaten. Die meisten Nutzer von quay.io arbeiten nicht mit dieser Funktion, sie wird jedoch aktiv von Red Hat OpenShift genutzt. OperatorHub innerhalb von OpenShift speichert alle Operatoren in der App Registry. Diese Operatoren sind die Grundlage für das Ökosystem von Arbeitslasten in OpenShift und das auf Partner ausgerichtete Betriebsmodell (im Rahmen der zweitagen Aktivitäten, Day 2).

Jeder OpenShift 4-Cluster verwendet Operatoren aus dem integrierten OperatorHub, um einen Katalog von verfügbaren Operatoren für die Installation zu veröffentlichen und Updates für bereits installierte bereitzustellen. Mit der wachsenden Beliebtheit von OpenShift 4 stieg auch die Anzahl der Cluster weltweit. Jeder dieser Cluster lädt die Inhalte der Operatoren, um den integrierten OperatorHub zu betreiben und verwendet die App Registry innerhalb von quay.io als Backend. Auf der Suche nach der Ursache des Problems haben wir übersehen, dass mit dem allmählichen Anstieg der Beliebtheit von OpenShift auch die Last auf eine der selten verwendeten Funktionen von quay.io zunahm..

Wir haben eine Analyse des Verkehrstransfers des App-Registrys durchgeführt und in den Code des Registers geschaut. Dabei traten sofort Mängel zutage, aufgrund derer die Datenbankabfragen suboptimal formuliert wurden. Bei geringer Last verursachten sie keine Probleme, jedoch wurden sie bei Anstieg der Last zur Quelle von Problemen. Der App Registry hatte zwei problematische Endpunkte, die schlecht auf die steigende Last reagierten: der erste lieferte eine Liste aller Pakete im Repository, der zweite gab alle Blobs für ein Paket zurück.

Ursachenbeseitigung

Die gesamte nächste Woche verbrachten wir mit der Optimierung des Codes des App Registrys und seiner Umgebung. Offensichtlich ineffiziente SQL-Abfragen wurden überarbeitet, unnötige Befehlsaufrufe beseitigt, tar (der bei jedem Abruf von Blobs gestartet wurde), überall, wo möglich, wurde Caching hinzugefügt. Anschließend fand ein umfangreicher Leistungstest statt, und die Geschwindigkeit des App Registrys vor und nach den Änderungen wurde verglichen.

API-Anfragen, die zuvor bis zu eine halbe Minute in Anspruch nahmen, wurden nun in Millisekunden ausgeführt.In der folgenden Woche implementierten wir die Änderungen in der Produktion, und seitdem funktioniert quay.io stabil. In der Zwischenzeit gab es mehrere plötzliche Verkehrsspitzen am Endpunkt des App Registrys, aber die vorgenommenen Verbesserungen verhinderten Datenbankausfälle.

Was haben wir gelernt?

Es ist klar, dass jeder Dienst bestrebt ist, Ausfallzeiten zu vermeiden. In unserem Fall glauben wir, dass die kürzlichen Ausfälle dazu beigetragen haben, quay.io zu verbessern. Wir haben einige grundlegende Lektionen gelernt, die wir teilen möchten:

  1. Daten darüber, wer und wie Ihr Dienst genutzt wird, sind niemals überflüssig.Da Quay „einfach funktionierte“, hatten wir nie das Bedürfnis, Zeit mit der Optimierung des Verkehrs und dem Lastmanagement zu verbringen. Das erzeugte ein falsches Gefühl der Sicherheit, dass der Dienst unbegrenzt skalierbar sei.
  2. Wenn ein Dienst ausfällt, ist die Wiederherstellung seiner Funktionstüchtigkeit die höchste Priorität.. Da Quay während des ersten Ausfalls weiterhin unter einer blockierten Datenbank litt, hatten unsere Standardverfahren nicht den gewünschten Effekt und wir konnten den Dienst mit deren Hilfe nicht wiederherstellen. Dies führte zu einer Situation, in der Zeit für die Analyse und Datensammlung aufgewendet werden musste, in der Hoffnung, die Ursache zu finden — anstatt all unsere Anstrengungen auf die Wiederherstellung der Funktionsfähigkeit zu konzentrieren.
  3. Bewerten Sie die Auswirkungen jeder Funktion des Dienstes. Kunden haben das App-Registry selten genutzt, sodass es für unser Team keine Priorität hatte. Wenn bestimmte Funktionen eines Produkts kaum benutzt werden, treten ihre Bugs selten auf und die Entwickler hören auf, den Code zu überwachen. Es ist leicht, dem Missverständnis zu erliegen, dass es so sein sollte — bis plötzlich diese Funktion im Mittelpunkt eines großangelegten Vorfalls steht.

Was folgt jetzt?

Die Arbeit an der Stabilität des Dienstes hört niemals auf, und wir verbessern ihn ständig. Die Verkehrsmengen auf quay.io wachsen weiter, und wir sind uns bewusst, dass wir alles tun müssen, um das Vertrauen unserer Kunden zu rechtfertigen. Daher arbeiten wir derzeit an den folgenden Aufgaben:

  1. Bereitstellung von nur-lesenden Datenbank-Replikaten, um dem Dienst zu helfen, den entsprechenden Verkehr im Falle von Problemen mit der Hauptinstanz RDS zu bewältigen.
  2. Aktualisierung der RDS-Instanz. Die aktuelle Version ist an sich kein Problem. Vielmehr möchten wir einfach die falsche Spur beseitigen (die wir während des Ausfalls verfolgt haben); die Software aktuell zu halten, wird einen weiteren Faktor im Falle zukünftiger Ausfälle ausschließen.
  3. Zusätzliches Caching im gesamten Cluster. Wir suchen weiterhin nach Bereichen, in denen Caching dazu beitragen kann, die Last auf die Datenbank zu reduzieren.
  4. Hinzufügung einer Webanwendungs-Firewall (WAF), um zu sehen, wer und warum sich mit quay.io verbindet.
  5. Ab dem nächsten Release werden die Red Hat OpenShift-Cluster auf App Registry verzichten zugunsten von Operator-Katalogen, die auf Container-Images basieren, die auf quay.io verfügbar sind.
  6. Eine langfristige Alternative zur App Registry könnte die Unterstützung der Spezifikationen der Open Container Initiative (OCI) sein. Diese wird derzeit als native Funktion von Quay implementiert und wird Benutzern zur Verfügung stehen, sobald die Spezifikation endgültig vereinbart ist.

Alle oben genannten Punkte sind Teil der fortlaufenden Investitionen von Red Hat in quay.io, während wir von einem kleinen, „start-up-ähnlichen“ Team zu einer ausgereiften Plattform übergehen, die von SRE verwaltet wird. Wir wissen, dass viele unserer Kunden, einschließlich Red Hat, auf quay.io in ihrem täglichen Betrieb angewiesen sind und bemühen uns, so transparent wie möglich in Bezug auf kürzliche Ausfälle und unsere anhaltenden Bemühungen, uns zu verbessern, zu sein.

P.S. vom Übersetzer

Lesen Sie auch in unserem Blog:

Quelle: habr.com

60GB SSD 8Gb DDR4