Spotify zur Diagnose von Kaskadenfehlern
Krisensituationen haben nicht immer ein tragisches Ende, schließlich braucht es intelligente Risiken, um Innovationen zu schaffen. Für Nick Rockwell, CTO der New York Times, ist „gute Risikobereitschaft“ im Raum des Unbekannten angesiedelt und Scheitern kann ein positives Ergebnis sein – eine Lernerfahrung für die Zukunft.
Wir haben in dieser Serie Berichte von technischen Führungskräften geteilt, zum Beispiel von Seth Vargo von HashiCorp darüber, wie man einen Systemausfall übersteht, und von Kenton Jacobsen, wie man bei Vogue schnell versagen (und noch schneller Fehler beheben) kann. Wir haben gelernt, dass selbst die routinemäßigsten Änderungen (wie der Neustart einer Datenbank oder der Wechsel des Backends) manchmal zu unerwarteten Fehlern führen können. Wir wissen aber auch, dass versierte Teams bereits über die nötigen Tools und Prozesse verfügen, um diese Probleme an Ort und Stelle zu lösen. In diesem Blogpost erfahren Sie, wie Niklas Gustavsson, Principal Engineer bei Spotify, nach einer eigentlich routinemäßigen Änderung auf nicht abspielbare Live-Inhalte (in der Produktivumgebung und für Endnutzer zugänglich) gestoßen ist, welche Lehren er daraus gezogen hat und welches sein bevorzugtes Debugging-Tool ist.
Spotify überträgt Audioinhalte für ältere Systeme (d. h. Nutzer älterer Spotify Clients) mit einer leicht angepassten nginx Software, die als „Produktionsspeicher“ bezeichnet wird. Es funktioniert so: Ein Client kommuniziert mit einem Zugangspunkt (einem Perimeterservice, der die Authentifizierung und die Weiterleitung von Inhalten verwaltet), der seinerseits mit dem Produktionsspeicher kommuniziert. Der Produktionsspeicher kommuniziert wiederum mit einem Proxy, der die Information an den Hauptspeicher weiterleitet (auch als der Origin-Server für alle Audiodateien bekannt).
Das Backend-Speichersystem wurde in diesem Jahr auf Google Cloud Storage (GCS) umgestellt, einschließlich aller Audiodateien. Nachdem viele Petabytes an Daten zu GCS verschoben worden waren, wurde die Umstellung auf GCS als Origin durch Umleitung des Proxys vorgenommen. Dies hätte eigentlich ein Leichtes sein müssen, weil Google die gleichen APIs anbietet wie S3, die bisherige Lösung.
Spotify hatte diese neuen Systeme zwar getestet, aber nach der Umstellung erhielt das Team Meldungen aus Australien und Neuseeland, dass es neue – aber nicht abspielbare – Inhalte in ihrem Service gab. Es ist verständlich, dass Künstler und Labels „nervös werden“, wenn neue Inhalte nicht abgespielt werden können. Niklas Gustavsson erstellte eine Störungsmeldung, um das Problem zu verfolgen. Dann griff er auf sein „bevorzugtes Debugging-Tool“ – ngrep – zurück, das den rohen Netzwerk-Traffic, der in den und aus dem Server fließt, aufdeckt und jeden Traffic in Echtzeit aufzeichnet, der einem bestimmten Muster entspricht, so wie ein reguläres grep dies für Dateien auf Ihrem lokalen System tut.
ngrep half dabei, festzustellen, dass bei den Antworten von GCS die Accept-Ranges: bytes
-Antwort-Header fehlten. Zwar wurden bei den Anfragen an GCS keine Ranges verwendet, doch dies war der einzige Unterschied zwischen GCS und S3, sodass eine weitere Untersuchung gerechtfertigt war.
Auch wenn nginx keine Bereichsanfragen an GCS stellt, tun dies sowohl die Spotify Clientanwendungen als auch der Zugangspunkt zwischen den Clients und nginx. Standardmäßig erkennt nginx, dass es auf Bereichsanfragen antworten kann, indem es bestätigt, dass das zwischengespeicherte Objekt den Accept-Ranges
-Antwort-Header hat. Der Header fehlte nun, deshalb antwortete nginx auf Bereichsanfragen mit einem HTTP-Statuscode 200 und dem gesamten angeforderten Objekt anstatt mit einem HTTP-Statuscode 206 und dem für den abgerufenen Bereich zutreffenden Teilinhalt. Dies ist ein zulässiges und völlig konformes Verhalten, aber eben eine nginx-Antwort, die anders war als zuvor, was zu Problemen in den nachgelagerten Bereichen führte.
Infolge der Beantwortung mit der kompletten Musikdatei stellte sich also heraus, dass nachgelagert zwei Fehler existierten: Der Zugangspunkt war nicht dafür ausgelegt, mit nicht-teilweisen Antworten umzugehen, und sendete eine Antwort an den Client mit falscher Inhaltslänge
. Die Clientanwendung konnte mit der falschen Inhaltslänge
wiederum nichts anfangen, was letztlich dazu führte, dass man die Tracks nicht abspielen konnte.
Das Team konnte die Probleme glücklicherweise beheben, indem es nginx so konfigurierte, dass es Bereichsanfragen beachtet und mit Teilinhalten antwortet (wie zuvor), selbst wenn es die Inhalte von Upstream ohne Accept-Ranges
-Header erhielt. Mit den in nginx zwischengespeicherten Dateien konnte das Team außerdem prüfen, bei welchen Dateien der Antwort-Header fehlte, und diese aus dem System bereinigen.
Rückverfolgung
Nach dieser Störung gingen Niklas Gustavsson und sein Team die anderen Teile ihrer Verteilerkette durch, um sicherzustellen, dass alles in Ordnung war. Die Neukonfiguration von nginx löste die Abhängigkeit vom Accept-Ranges
-Header. Und als zusätzliche Maßnahme hat man den Proxy zwischen nginx und GCS so konfiguriert, dass der Header ohnehin immer hinzugefügt wird (da GCS das Setzen des Headers nicht standardmäßig unterstützt.)
Den Fehler im Zugangspunkt hat man ebenfalls behoben, sodass er nun vollständige Antworten auf Bereichsanfragen korrekt verarbeiten kann. Und obwohl dies bedeuten würde, dass der Zugangspunkt nicht mehr mit einer falschen Inhaltslänge auf den Client reagiert, arbeitet das Team daran, auch den Client zu reparieren, sodass er mit dieser Art von außergewöhnlichen Fehlern in Zukunft tatsächlich („auf elegante anstatt auf brutale Weise“) umgehen kann.
Wir werden in den kommenden Monaten über weitere Krisensituationen berichten, halten Sie also Ausschau danach.