Lehren aus 20 Jahren Site Reliability Engineering
(sre.google)- Google SRE fasst Erfahrungen zusammen, wie Zuverlässigkeit in einer Umgebung gesteigert wurde, die von kleinen Rechenzentren und Python-Skript-basiertem Betrieb auf eine mehr als 1.000-fache Compute-Größe und eine mehr als 10.000-fache Netzwerkgröße gewachsen ist
- Bei der Störungsreaktion steht nicht die schnelle Maßnahme an erster Stelle, sondern die Sicherheit der Mitigation; falsche Wiederherstellungsabläufe können Ausfälle eher zu Kaskadenfehlern ausweiten, statt sie zu verringern
- Die Beispiele YouTube und Google Calendar zeigen die Notwendigkeit von Canary Deployments, die globale Änderungen begrenzen, eines sofort rückgängig machbaren Big Red Button sowie von Integrationstests, die reale Pfade validieren
- Wenn eine zentrale Abhängigkeit zusammenbricht, wie beim OAuth-Token-Ausfall 2017, geraten nicht nur Nutzer, sondern auch interne Reaktionsstrukturen ins Wanken; daher braucht es Backup-Kommunikationskanäle und graceful degradation
- Häufige Rollouts, automatisierte Mitigation, Disaster-Recovery-Übungen und Hardware-Diversität sind praktische Prinzipien, um in komplexen verteilten Systemen die MTTR zu senken und Single Points of Failure zu vermeiden
Wie sich der Maßstab von Google SRE über 20 Jahre verändert hat
- Vor 20 Jahren betrieb Google zwei kleine Rechenzentren, jedes mit einigen Tausend Servern; zwei 2,4G-Netzwerklinks waren ringförmig miteinander verbunden
- Der Betrieb stützte sich damals stark auf Python-Skripte wie
Assigner,AutoreplacerundBabysittersowie auf Konfigurationsdateien mit einzelnen Servernamen - Eine kleine Maschinendatenbank namens MDB wurde genutzt, um Informationen zu einzelnen Servern zu organisieren und laufend zu pflegen
- Heute sind die Computing-Leistung um mehr als das 1.000-Fache und das Netzwerk um mehr als das 10.000-Fache gewachsen, während der Betriebsaufwand pro Server gesunken ist und die Zuverlässigkeit des Service-Stacks gestiegen ist
- Die Betriebstools haben sich von einer Sammlung von Skripten zu einem Service-Ökosystem und weiter zu einer integrierten Plattform entwickelt, die grundlegende Zuverlässigkeit bereitstellt
Reaktionsprinzipien aus dem YouTube-Ausfall
- 2016 erlebte YouTube aufgrund eines Bugs in einem verteilten In-Memory-Caching-System einen 15-minütigen globalen Ausfall, wodurch die Bereitstellung von Videos unterbrochen wurde
- Mitigationsmaßnahmen müssen zur Schwere des Ausfalls passen
- Während des YouTube-Ausfalls behob ein riskantes Load-Shedding-Verfahren den Ausfall nicht, sondern erzeugte Kaskadenfehler
- Riskante Mitigation kann im besten Fall einen Ausfall beheben, im schlimmsten Fall aber fehlerhaft wirken und die Ausfallzeit verlängern
- Selbst in Situationen, die ein Umgehen von Standardverfahren nahezulegen scheinen, sollte zunächst die Schwere beobachtet und bewertet werden, bevor eine Maßnahme gewählt wird
- Wiederherstellungsmechanismen müssen vor echten Notfällen ausreichend getestet werden
- Ein riskantes Mitigationsverfahren während eines Ausfalls erstmals auszuführen, ist wie bei einer Brandflucht aus einem Hochhaus zum ersten Mal eine Leiter zu benutzen
- Vorab muss geprüft werden, ob das Wiederherstellungsverfahren tatsächlich das Nötige leistet und ob die zuständigen Personen wissen, wie es auszuführen ist
- Das Testen selbst reduziert auch das Risiko bei der Durchführung der jeweiligen Maßnahme
- Alle Änderungen sollten mit Canary Deployments im Wirkungsbereich begrenzt werden
- Eine Änderung der Caching-Konfiguration legte den YouTube-Dienst durch unbeabsichtigte Folgen 13 Minuten lang weitgehend lahm
- Wäre die globale Änderung per Canary-Strategie schrittweise ausgerollt worden, hätte der Ausfall vor globalen Auswirkungen begrenzt werden können
- Als verwandte Materialien gibt es das Paper zur Canary-Strategie und ein SREcon-Vortragsvideo
Rollback und Tests aus dem Calendar-Ausfall
- Für riskante Änderungen braucht es einen vorab definierten Big Red Button
- Der Big Red Button ist eine einfache, leicht ausführbare Sicherheitsvorkehrung, die die Ursache eines unerwünschten Zustands rückgängig macht
- In einem Fall zog ein Engineer den Stecker seines Desktop-Computers, bevor eine Änderung weiter verbreitet wurde, und verhinderte so knapp einen großen Ausfall
- Bei der Planung wichtiger Rollouts sollte man die Frage „Was ist mein Big Red Button?“ berücksichtigen; für alle Service-Abhängigkeiten sollte es eine im Notfall ausführbare Vorrichtung geben
- Ein verwandter Beitrag ist Generic Mitigations
- Unit-Tests allein reichen nicht aus; es braucht Integrationstests
- Unit-Tests prüfen, ob einzelne Komponenten wie erwartet funktionieren, bilden aber Laufzeitumgebung und Produktionsanforderungen nicht vollständig nach
- Integrationstests werden genutzt, um zu validieren, ob Jobs und Tasks einen Cold Start durchführen können und ob Komponenten gemeinsam das gewünschte System ergeben
- Beim Calendar-Ausfall unterschied sich der Testpfad vom tatsächlichen Nutzungspfad; obwohl es viele Tests gab, halfen sie daher nicht, zu bewerten, wie sich die Änderung in der Realität verhalten würde
OAuth-Token-Ausfall 2017 und Betriebskontinuität
- Im Februar 2017 wurden wegen nicht nutzbarer OAuth-Tokens Millionen Nutzer von Geräten und Diensten abgemeldet, und 32.000 OnHub- und Google-WiFi-Geräte führten einen Werksreset durch
- Aufgrund fehlgeschlagener Logins stiegen manuelle Anfragen zur Kontowiederherstellung um das 10-Fache; Google brauchte rund 12 Stunden, um sich vollständig von dem Ausfall zu erholen
- Für die Störungsreaktion braucht es Backup-Kanäle, die von den primären Kommunikationskanälen getrennt sind
- Damals erwarteten Teams, den Ausfall über Google Hangouts und Google Meet managen zu können
- In einer Situation, in der 350 Millionen Nutzer von Geräten und Diensten abgemeldet waren, war es jedoch nicht angemessen, sich auf Google-Dienste zu verlassen
- Backup-Kommunikationskanäle mit getrennten Abhängigkeiten müssen vorbereitet und getestet werden
- Dienste sollten auch in Ausnahmesituationen per graceful degradation weiter funktionieren
- Es reicht nicht aus, Verfügbarkeit nur in „vollständig normal“ oder „vollständig ausgefallen“ zu unterteilen
- Wenn im Degradationsmodus minimale Funktionen weiterlaufen, kann dies eine konsistentere Nutzererfahrung bieten
- Degradation muss für Nutzer nicht sichtbar sein; Dienste sollten so entworfen werden, dass sie auch unter außergewöhnlichen Bedingungen weiterarbeiten
Katastrophen, Automatisierung, Rollouts und Hardware-Diversität
- Disaster Resilience und Recovery-Tests sind Kernelemente einer Business-Continuity-Strategie
- Resilienztests prüfen, ob ein Dienst oder System auch bei Fehlern, Verzögerungen und Unterbrechungen standhalten kann
- Recovery-Tests prüfen, ob ein Dienst nach einem vollständigen Shutdown wieder in einen normalen Zustand zurückkehren kann
- Wie in Weathering the Unexpected sollten auch Extremsituationen wie Naturkatastrophen oder Cyberangriffe angenommen werden
- Nützlich sind auch Übungen, bei denen Teams in Form von Tabletop Games Szenarien wie „Was passiert, wenn ein Teil der Netzwerkverbindungen unerwartet ausfällt?“ durchgehen
- Bei Ausfällen mit klaren Signalen kann Mitigationsautomatisierung ein Mittel sein, um die MTTR zu senken
- Im März 2023 fielen mehrere Netzwerkgeräte in mehreren Rechenzentren fast gleichzeitig aus, was zu großflächigem Paketverlust führte
- Während dieses 6-tägigen Ausfalls waren etwa 70 % der Dienste je nach Standort, Service-Last und Konfiguration zum Zeitpunkt des Netzwerkfehlers in unterschiedlichem Ausmaß betroffen
- Anteil betroffener Dienste: {p:70}
- Wenn das Signal für einen bestimmten Fehler eindeutig ist, lassen sich manuelle Mitigationsmaßnahmen automatisch starten und so die MTTR senken
- Manchmal ist es besser, zuerst Auswirkungen auf Nutzer zu vermeiden und anschließend die Ursache zu analysieren
- Je länger die Abstände zwischen Rollouts sind, desto schwieriger wird es, die Sicherheit einer Änderung zu beurteilen
- Im März 2022 verhinderte ein Ausfall des Zahlungssystems, dass Kundentransaktionen abgeschlossen wurden, und der Pokémon GO Community Day wurde verschoben
- Ursache war die Entfernung eines einzelnen Datenbankfelds; da die Nutzung dieses Felds im Code entfernt worden war, schien die Änderung sicher zu sein
- Wegen langsamer Rollout-Zyklen in Teilen des Systems verwendete das Live-System dieses Feld jedoch weiterhin
- In komplexen Systemen mit mehreren Komponenten machen lange Rollout-Verzögerungen die Sicherheitsbewertung einer bestimmten Änderung sehr schwierig
- Häufige Rollouts zusammen mit geeigneten Tests können unerwartete Fehler dieser Art reduzieren
- Eine einzige globale Hardware-Version kann zu einem Single Point of Failure werden
- Wenn eine wichtige Funktion ausschließlich Geräten eines Modells überlassen wird, können Betrieb und Wartung einfacher werden
- Tritt jedoch bei diesem Modell ein Problem auf, wird diese wichtige Funktion nicht mehr ausgeführt
- Im März 2020 legte ein Netzwerkgerät mit einem unentdeckten Zero-Day-Bug diesen Bug durch eine Änderung im Traffic-Muster offen; weil dasselbe Modell und dieselbe Version im gesamten Netzwerk eingesetzt wurden, kam es zu erheblichen regionalen Ausfällen
- Da es mehrere Network Backbones gab, konnte Traffic mit hoher Priorität über alternative Pfade geleitet werden, die noch funktionierten, und ein vollständiger Ausfall wurde vermieden
- Potenzielle Bugs in kritischer Infrastruktur können verborgen bleiben, bis ein scheinbar harmloses Ereignis eintritt; vielfältige Infrastruktur zu erhalten kann den Unterschied zwischen einer problematischen Störung und einem Totalausfall ausmachen
1 Kommentare
Meinungen auf Hacker News
Der Artikel ist hervorragend und wirkt breit anwendbar. Es gibt kaum Stellen nach dem Motto „Das gilt nur bei Google“.
Kommunikationskanäle, Ersatzkanäle und sogar Ersatzkanäle für die Ersatzkanäle sind wirklich wichtig. Bei Netflix haben wir bei der Auswahl von Systemen, die während eines Ausfalls genutzt werden, immer geprüft, ob der Anbieter nicht auf AWS läuft; bei reddit hatten wir für den Fall, dass das üblicherweise genutzte IRC ausfällt, ein Ersatz-IRC auf einem Server im Büro.
Ich habe gehört, dass auch Google einen Ersatz-IRC-Server auf AWS hat, aber das könnte auch nur eine Legende sein. Entscheidend ist, einen zusätzlichen Kommunikationskanal zu haben, der möglichst unabhängig von der eigenen Infrastruktur ist.
Dieses Team lag auf dem kritischen Pfad. Wenn unser System der Grund für den Alarm war, war die Wahrscheinlichkeit keineswegs gering, dass nicht nur Google Meet, sondern auch Google.com gleichzeitig unten war. Wegen Gmail ging auch E-Mail nicht, wegen Google Fi auch das Diensthandy nicht, und der ISP zu Hause war Google Fiber/Webpass, also brauchten wir noch weitere Ersatzebenen.
Deshalb gibt es bei Google tatsächlich Ersatz-IRC-Server für die Kommunikation. Ich werde nicht sagen, wo sie stehen, aber genau aus diesem Grund wurden sie ausdrücklich außerhalb der Google-Infrastruktur platziert.
Im Sinne von „breit anwendbar und nicht nur etwas für Google“ war etwas, das ich anderswo fast nie gesehen habe, der Operations Panic Room: ein gesicherter Raum mit einem Ersatz-VPN zur Produktionsumgebung.
Eines Tages verhielt sich das Produktions-SAN seltsam, woraufhin das On-Premises-Rechenzentrum ausfiel, und Atlassian starb gleich mit. Kein Jira, kein Confluence, wahrscheinlich auch kein CI/CD, keine sauber dokumentierten Wiederherstellungsprozeduren, nur verstreutes Stammeswissen.
Die Leute waren wütend, und das zu Recht. Kundennahe Systeme und Infrastruktursysteme in denselben Korb zu legen, ist wirklich gefährlich.
Zumindest war das vor zwei Jahren so, als ich dort noch gearbeitet habe.
Irgendwann würde ich gern die Lösung für das Problem eines vollständigen Cold Starts hören. Unternehmen mit einem riesigen eigenen Stack haben zirkuläre Abhängigkeiten in der Kerninfrastruktur.
Bei Software-defined Networking muss bestimmte Software laufen, damit das Paket-Routing wieder gestartet werden kann; plattenlose Maschinen brauchen Storage zum Booten; Authentifizierungsdienste benötigen Zugriff auf Storage, um die Vergabe von Sicherheitsberechtigungen zu bootstrappen.
Derzeit löst man das, indem man mehrere unabhängige Regionen betreibt und ein vollständig abgeschaltetes Rechenzentrum aus bestehender Infrastruktur heraus bootstrapped. Aber ich habe noch nie gehört, dass jemand den gesamten Stack aus einem komplett stromlosen Zustand wieder hochgefahren hätte.
Als Facebook vor ein paar Jahren sein Produktionsnetzwerk vollständig kaputtmachte, waren die Maschinen immer noch eingeschaltet, und intern gab es noch teilweise Konnektivität. Wenn etwa ein massiver Sonnensturm das Stromnetz weltweit lange lahmlegte und selbst die Generatoren vollständig erschöpft wären, gibt es keine Garantie, dass Clouds wie AWS oder GCP zwangsläufig wieder hochkommen.
Vermutlich gibt es kleine dedizierte Rechenzentren mit hervorragender Notstromversorgung und der Fähigkeit, sich vollständig von Überspannungen im Stromnetz zu isolieren.
Am oberen Ende des Stacks war das nützlich, um Abhängigkeiten nachzuverfolgen, die Bibliotheksautoren stillschweigend hinzugefügt hatten; am unteren Ende half es sicherzustellen, dass Dinge, die ganz unten sein sollten, auch wirklich dort blieben.
Außerdem wurden virtuelle automatische Cluster hoch- und heruntergefahren, damit dokumentierte Verfahren nicht veralteten. In meinen sechs Jahren als SRE habe ich gesehen, wie diese Prozedur von 90 Tagen auf weniger als eine Stunde schrumpfte.
Auch Dinge wie globales Verschlüsselungs-Key-Management, das physische Objekte benötigt, wurden regelmäßig von Grund auf neu gestartet, und die jährlichen DiRT-Übungen sollten sicherstellen, dass keine einzelne Person, kein Team und kein Büro eine Voraussetzung für den fortlaufenden Betrieb der Systeme war.
Wenn man spät damit anfängt, ist es sehr schmerzhaft; wenn man es von Anfang an tut, gewöhnt man sich schnell daran und findet brechende Änderungen oder merkwürdige Abhängigkeiten früh.
Das lässt sich auch auf Hardware anwenden. Die Architektur ändert sich so, dass sie damit umgehen kann, wenn etwas herausgezogen oder zurückgesetzt wird. Man braucht mehr Automatisierung, Versionsverwaltung und Änderungsmanagement, und dadurch werden nicht nur Ausfälle verhindert und Wiederherstellungen schneller, sondern die gesamte Arbeit wird schneller und einfacher. Das ist ein großer Kulturwandel.
Soweit ich mich erinnere, gelten Teile des Ansatzes als vertrauliche Informationen, daher werde ich nicht näher darauf eingehen.
Interessant wäre auch, welches Stromnetz die meisten Cold Starts durchgeführt hat. Idealerweise sollte ein solches Netz darin bereits gut sein. Ich vermute, irgendwo in der Karibik oder in Afrika.
Allerdings könnte ein Cold Start eines kleinen Stromnetzes, etwa auf einer abgelegenen Insel mit einem Dieselgenerator und Solarstrom, zu einfach sein, um eine gute Fallstudie abzugeben.
Klar ist, dass das Internet selbst nicht wie ein Wechselstromnetz kalt gestartet werden kann. Es gibt zu viele AS. Wenn man kurz darüber nachdenkt, wofür AS steht, versteht man, warum ein koordinierter und geprobter Cold Start unmöglich ist.
Wer tiefer in dieses Thema einsteigen möchte: Ich habe Googles Building Secure and Reliable Systems fast durchgelesen; das ist keine leichte Lektüre, sondern eher ein richtiges Lehrbuch.
Es ist ein ziemlich interessantes Buch, und vieles darin wirkt wie gesunder Menschenverstand, aber wie es so schön heißt, ist „gesunder Menschenverstand“ selbst schon ein Widerspruch; es war jedenfalls nützlich, das gesamte Wissen einmal am Stück aufzufrischen.
Ich habe kürzlich gehört, dass einige Unternehmen ihre SRE-Organisationen aufgelöst und die Leute in SWE-Teams verschoben haben. Gerüchten zufolge haben LinkedIn, Adobe und Robinhood das getan.
Das brachte mich zu der Frage, ob SRE ein Nebenprodukt der Bubble-Ökonomie mit viel leichtem Geld war. Könnte man nicht ohne den großen Aufwand eines separaten SRE-Teams auskommen?
So wie Systemadministratoren oder QA-Tester weitgehend verschwunden sind und viele Aufgaben an Softwareentwicklungsteams übergingen, frage ich mich, ob es SRE in zehn Jahren noch geben wird.
Aber angesichts der aktuellen Entlassungswellen achten nicht viele Unternehmen darauf. Die Tendenz, Entwickler auch auf Probleme anzusetzen, die nicht zu ihrem eigentlichen Spezialgebiet gehören, ist ein Branchentrend, der nicht verschwinden wird und in Abschwungphasen noch deutlicher wird.
Full-Stack-Entwickler sind ein gutes Beispiel dafür, zwei Rollen zusammenzulegen, ohne dafür das Doppelte zu bezahlen.
Der übrige Punkt stimmt meiner Meinung nach aber weiterhin. Durch DevOps ist das Fähigkeitsspektrum, das Entwickler brauchen, heute breiter geworden und überschneidet sich stark mit SRE. Unternehmen werden wahrscheinlich SRE-Teams verkleinern und die Verantwortung auf Entwickler verteilen.
Ein weiterer wichtiger Grund ist Automatisierung. Wenn man die verlinkte Site länger liest, sieht man, dass SREs in den frühen Tagen von Google viel Handarbeit leisteten, etwa Graphen manuell beobachteten und Deployments begleiteten.
Damals waren selbst bei Google die Systeme noch nicht ausreichend automatisiert, deshalb waren SREs unverzichtbar. Die Sisyphus-Geschichte https://www.usenix.org/sites/default/files/conference/protec... vermittelt in gewissem Maß, wie Googles anfängliches Scheitern bei der Einführung standardisierter Automatisierung die Jobsicherheit von SREs garantierte.
Es ist nicht logisch, den Betrieb der Software, die man selbst geschrieben hat, an jemand anderen abzugeben. Man kann SWEs in den On-Call-Dienst nehmen. Wenn jemand glaubt, dass manuelle Arbeit die beste Lösung ist, soll er sie selbst machen; und wenn das das Niveau ist, sollte man ihn als schlechten Engineer entlassen.
Es ist seltsam, in Interviews so streng zu sein und dann nicht zu wissen, wie der Computer funktioniert, auf dem man programmiert. Dinge wie die Funktionsweise von Betriebssystemen gehören schon zum Grundstudium; ebenso seltsam ist es, das an viele Rollen und Titel abzuschieben, die überwiegend von autodidaktischen Systemadministratoren geprägt sind.
Alle guten SWEs, die ich kenne, wussten, wie Betriebssysteme, Computer und Netzwerke funktionieren.
Die Dinge, die SRE heute typischerweise macht – allgemeine Automatisierung, Bereitstellung von Entwicklerwerkzeugen, Verbesserung der Developer Experience –, wandern in Plattform-Teams. Ich denke, die Rolle wird sich künftig stark verändern.
Ein einzelnes SRE-Team kann mehrere Entwicklungsteams unterstützen, und Entwicklungsteams verbringen oft nur wenig Zeit mit komplexer Infrastruktur oder Aspekten verteilter Systeme, weil das nicht ihr alltägliches Sorgenfeld ist.
Deshalb ist es sinnvoll, eine Infrastrukturorganisation zu haben, die als andere Einheit als spezialisierte Entwicklungsteams agiert. Ob man sie SRE nennt, SRE-SWE-Team oder einfach Infrastruktur: Ab einer gewissen Größe gibt es so viele teamübergreifende Anliegen, dass diese Trennung günstiger wird.
Mit dedizierten SREs hat man echte Experten für Betrieb, zugehörige Systeme, Tools und Alerts sowie klare Verantwortung für die Ergebnisse. Weil sie die Systeme, die sie betreuen, aber nicht vollständig besitzen, können organisatorische Probleme entstehen.
Es kann heißen: „Wir wollen X veröffentlichen, aber SRE ist dagegen“ oder umgekehrt, und Nicht-SREs könnten sich der Verantwortung für schwer unterstützbaren Code entziehen.
Engineering-Teams ohne SREs können umgekehrt solche organisatorischen und sozialen Probleme reduzieren, aber betriebliche Zuverlässigkeit wird dann nur eine von vielen Prioritäten.
In der Praxis entscheiden sich meiner Ansicht nach viele Unternehmen gerade dafür, Zuverlässigkeit als Geschäftsergebnis nicht besonders hoch zu gewichten – besonders dann, wenn die Opportunitätskosten für Feature-Entwicklung steigen.
Automatische Mitigation muss man wirklich lange durchdenken. In meinen 30 Berufsjahren habe ich mehrfach gesehen, wie automatische Mitigation ein Problem noch verschlimmert hat. Deshalb sollte man sorgfältig abwägen, ob Self-Healing wirklich nötig ist.
2014 habe ich eine mobile Crash-Reporting-Lösung für den internen Gebrauch im Unternehmen gebaut; ein Teil des Backends lief auf einem einzelnen Server, der Redis als Single Point of Failure hatte. Der Failover-Prozess war halbautomatisch: Ein Mensch musste zunächst prüfen, ob der Alarm berechtigt war, und ihn dann starten.
Wenn das System ausfiel, gab es keinen echten finanziellen Verlust; im schlimmsten Fall hatten Mobile-App-Entwickler kurzzeitig Unannehmlichkeiten. In 10 Jahren Betrieb konnte man die Fälle, in denen ein Failover nötig war, an zwei Fingern abzählen.
Obwohl das System kein SLA hatte, war seine Uptime besser als die von deutlich wichtigeren internen Systemen.
Als Gegenbeispiele kann man sich GitHub-Fälle ansehen: https://github.blog/2023-05-16-addressing-githubs-recent-ava..., https://github.blog/2018-10-30-oct21-post-incident-analysis/, https://www.datacenterknowledge.com/archives/2012/12/27/gith...
Natürlich betreibt GitHub das in einem viel größeren Maßstab. Der Punkt ist: Redundanz und automatische Mitigation erhöhen die Komplexität und funktionieren per Definition in unerwarteten Situationen in einem Zustand, der kaum getestet wurde.
Man sollte also SLA und Ausfallkosten betrachten und sie gegen die Komplexität abwägen, die man hinzufügt, um Ausfälle zu verhindern. Um 1998 herum habe ich zwei NetApp-Geräte zu einer Hochverfügbarkeitskonfiguration zusammengeschaltet; als eines ausfiel, hat es auch noch alle Platten des anderen ruiniert. Das war meine erste Lektion.
Etwa zur gleichen Zeit passierte mir Ähnliches mit zwei Cisco-PIX-Firewalls, und seitdem bin ich bei Hochverfügbarkeit sowie automatischem Failover und automatischer Mitigation immer vorsichtig geblieben.
Mich interessiert, wie Big Red Buttons und absichtliche Graceful Degradation in der Praxis gehandhabt werden. Besonders interessiert mich, wie man sicherstellt, dass sie auch dann funktionieren, wenn das System gerade Probleme hat.
Nutzt man zum Beispiel datenbankbasierte Feature Flags, und wenn ja: Was passiert, wenn die Datenbank selbst oder die Zugriffs-API überlastet ist?
Oder nutzt man statische Start-Flags wie Umgebungsvariablen, und wie stellt man in diesem Fall sicher, dass sie schnell genug ausgerollt werden? Oder gibt es einen ganz anderen Ansatz?
Auch wenn man in Teilen des kritischen Pfads keine Redundanz einsetzt, kann das besser sein, wenn das System so einfach ist, dass alle Maintainer es im Kopf behalten können, und es sich leicht neu starten oder zurückrollen lässt.
Sobald ein Unternehmen jedoch anfängt, Zusagen wie „Five Nines Uptime“ zu machen, braucht man eine gewisse Komplexität, um Systeme zu entwerfen, die diese Zusagen einhalten und zugleich Weiterentwicklung und Verbesserungen ermöglichen.
Bei Google wurden regelmäßig „Backend Drains“ durchgeführt, wenn ein bestimmter Cluster als nicht gesund galt, und es gab Systeme, die das auf der API-/Load-Balancer-Ebene schnell handhaben konnten.
Anderswo habe ich auch gesehen, dass das über Flags auf Anwendungsebene gelöst wurde. Mit Dingen wie
kubectl editist das eindeutig nicht ideal, aber es hat funktioniert.Erstens: Es einfach halten. Am besten ist etwas wie eine einfache Flag-Prüfung ohne ausgefeilte Logik oder komplexe Datenspeicher.
Zweitens: So nah wie möglich an die Quelle legen, aber dem Client nicht zu sehr vertrauen. Es kann alte Versionen, Verzögerungen bei der Verteilung und Bugs geben; daher ist es gut, wenn sowohl Client als auch Server einen Degradationsmodus wählen können, und wenn nur eine Seite möglich ist, ist die Serverseite besser.
Drittens: Häufig mit echtem Traffic testen. Vertraue nicht auf Testumgebungen; führe regelmäßige kleine Tests, etwa mit 0,1 %, sowie geplante große Tests durch. Wenn man es nicht getestet hat, wird es nicht funktionieren, wenn man es braucht; und wenn es vor einem Jahr funktioniert hat, ist die Wahrscheinlichkeit groß, dass es heute nicht mehr funktioniert. Ungetestete Vorrichtungen können mehr Schaden anrichten als Probleme lösen.
Angenommen, man fügt Hacker News eine neue Funktion hinzu, die neben Kommentaren Profilbilder anzeigt. Da man natürlich alles als Microservices gebaut hat, nehmen wir an, dass der Frontend-Page-Generator den Profil-Service aufruft, der Profil-Service eine Abfrage durchführt und dann den Ort des Bildes zurückgibt.
Als Teil des Release-Plans dokumentiert man ein Big-Red-Button-Verfahren, das zu befolgen ist, wenn die neue Komponente den Profil-Service oder den Bildspeicher überlastet. Konkret führt man auf der Netzwerkebene einen Befehl aus, der die Rate externer Requests meines Services begrenzt, und in einem Notfall setzt man sie vermutlich auf 0.
Die Abfrage schlägt fehl, aber der Page-Generator ist so entworfen, dass er graceful degradiert und den Kommentartext weiterhin ohne Profilbild rendert.
Das ist kein echtes Designdokument und auch kein Rat, wie man etwas bauen sollte, sondern nur eine Wachsmalstift-Skizze, um den Punkt zu erklären.
Ich habe das auch mit djbs CDB (constant database) gemacht; außerdem habe ich Fälle gesehen, in denen JSON-Konfigurationsdateien über eine API gepollt oder dbm/gdbm/Berkeleydb/leveldb verwendet wurden.
Dieser Ansatz lässt sich auch auf andere Big Red Buttons erweitern. Elegant ist das nicht, aber ich habe mehrfach Services betrieben, die prüften, ob eine Datei existiert, um zu entscheiden, ob sie Health Checks anbieten. Einen Node aus der Load-Balancer-Rotation zu nehmen, war so einfach wie das Anlegen einer Datei.
Entscheidend ist, dass das System bei einem Datenbankausfall standardmäßig die zuletzt bekannte gute Konfiguration verwendet.
Den Satz „Wiederherstellungsmechanismen müssen vor dem Notfall vollständig getestet werden“ möchte ich wirklich unterstreichen. Als jemand, der bei Google unerwartet zum SRE wurde und unternehmensweit dafür bekannt ist, eine doppelte Verneinung falsch verwendet zu haben, ist das eine enorm wichtige Sache, die man sofort richtig machen muss.
Wenn neugierige Googler intern nach meinem Nutzernamen suchen, können sie herausfinden, wie ich eine unermesslich große Wirkung erzeugt habe.
Die günstigste Methode, Ausfälle zu verhindern, ist, sie früh im Lebenszyklus abzufangen. Software-Bugs ähneln echten Insekten. Am Anfang steht das Ei, also die Idee für eine Änderung; die geschlüpfte Nymphe ist der erste POC. Wenn sie die Produktionsumgebung erreicht, ist sie ein ausgewachsenes Insekt.
Gibt es nicht noch Stadien vor dem Erwachsenenstadium? Genau. Eine Anwendung muss mehrere Phasen durchlaufen, bevor sie ausgereift ist. Es ist deutlich günstiger, einen Bug zu finden, bevor er ausgewachsen ist und Eier legt.
Wenn Canary Deployments schwierig sind und auch Rollbacks Probleme bereiten, muss man vor dem Produktions-Deployment mehr Tests einbauen. Man sollte Bugs so früh wie möglich auf möglichst viele Arten finden: Linter, Unit-Tests, End-to-End-Tests, Profiler, Synthetic Monitors, Read-only-Produktionsreplikas, Performance-Tests usw.
Feature Flags, Abwärtskompatibilität und Ähnliches sind ebenfalls nützlich, aber nichts schlägt Shift Left.
Wer an einer ähnlichen Liste aus der Perspektive von 15 Jahren SRE in FinTech, Banken, Hedgefonds und Kryptowährungen interessiert ist, dem sei dieser Beitrag empfohlen: https://x.com/alexpotato/status/1432302823383998471?s=20
Kostprobe: „25. Wenn es eine Rules Engine gibt, bei der es einfacher ist, eine neue Regel zu erstellen, als bestehende Regeln über Filterbedingungen zu finden, entstehen am Ende jede Menge doppelte Regeln.“
„Ein Engineer, der eine Änderung eingereicht hatte, die beinahe einen Ausfall verursacht hätte, verhinderte einen großen Ausfall gerade noch, indem er vor der Ausbreitung der Änderung den Stecker seines Desktop-Computers zog“ – was soll das überhaupt heißen?
Das führte dazu, dass Infra-SWEs keine echten Buttons bauten, sondern den ganzen Tag dumme CLIs schrieben. Als ich ging, änderte sich das schon deutlich.
Ich finde, Google sollte interne Ausfälle stärker öffentlich machen. Dieser Ausfall war intern besonders bekannt.
Selbst in enormem Maßstab können Shell-Tools und RPC-Client-CLIs ziemlich schnell Maschinen auf der ganzen Welt erreichen.
pssh-artigen Utility laufen ließ.Das war vor zehn Jahren, daher weiß ich nicht, ob es immer noch so genutzt wird, aber diese Methode war erstaunlich schnell. Es könnte etwas in dieser Art gewesen sein.
Aber vor 20 Jahren war das vermutlich häufiger, und in kleineren Organisationen kann es das auch heute noch geben.