Google Cloud-Ansatz für Veränderungen

Jedes Jahr interagieren Milliarden Nutzer mit den Produkten und Diensten von Google. Wichtige Angebote wie die Google Suche, Gmail, Maps, YouTube, Chrome und jetzt auch Google Cloud sind so nahtlos in das moderne Leben eingebunden, dass sie das Leben im 21. Jahrhundert prägen. Die globale Wirkung ist das Ergebnis der bewährten Qualität unserer Angebote und der Erwartung, dass Google immer verfügbar ist.

Bei Google Cloud führen wir kontinuierlich Codeänderungen in unseren Produkten und Diensten ein, um die Nutzerfreundlichkeit zu verbessern, die Sicherheit und Zuverlässigkeit zu erhöhen und die gesetzlichen Bestimmungen und Compliance-Anforderungen einzuhalten. Jede solche Änderung, egal wie groß oder klein, kann manchmal zu Problemen führen. Um dieses Risiko zu minimieren, legen wir großen Wert auf die Sicherheit von Änderungen während des gesamten Änderungszyklus.

In diesem Dokument wird erläutert, wie die Google Cloud-Teams auf den jahrzehntelangen Investitionen von Google in die Entwicklung aufbauen, um Best Practices für Zuverlässigkeit und Engineering-Standards zu implementieren, die die Erwartungen der Google Cloud-Kunden in Sachen Geschwindigkeit der Entwicklung und Zuverlässigkeit erfüllen.

Lebenszyklus einer Änderung bei Google Cloud

Die Google Cloud-Produktteams teilen einen Großteil des Verwaltungsprozesses und der Tools mit anderen Entwicklungsteams bei Google. Wir implementieren im Rahmen des Änderungsmanagements einen standardmäßigen Ansatz für die Softwareentwicklung, wobei Continuous Integration (CI) und Continuous Delivery (CD) priorisiert werden. Die CI umfasst häufig Vorschläge, Tests und Einreichungen von Änderungen, oft mehrmals täglich für ein bestimmtes Produkt oder einen bestimmten Dienst. CD ist eine Erweiterung der CI, bei der Entwickler kontinuierlich Release-Kandidaten basierend auf dem neuesten stabilen Snapshot einer Codebasis vorbereiten.

Bei diesem Ansatz werden Änderungen so schnell wie möglich, aber auch so sicher wie möglich in mehreren Phasen für Google Cloud-Kunden erstellt und verfügbar gemacht. Wir berücksichtigen die Sicherheit von Änderungen, bevor wir Code schreiben, und legen auch nach der Einführung von Änderungen in der Produktion weiterhin großen Wert auf Sicherheit. Unser Change-Management-Modell umfasst vier allgemeine Phasen: Design, Entwicklung, Qualifizierung und Einführung. Diese vier Phasen sind im folgenden Diagramm dargestellt und werden im Folgenden ausführlicher beschrieben:

Diagramm mit den Schritten für die Design-, Entwicklungs-, Qualifizierungs- und Einführungsphasen.

Von Grund auf sicher

Uns ist bewusst, dass selbst kleine Fehler zu Beginn des Entwicklungsprozesses später zu großen Problemen führen können, die sich erheblich auf die Nutzerfreundlichkeit auswirken können. Daher müssen alle größeren Änderungen mit einem genehmigten Designdokument beginnen. Wir haben eine gemeinsame Designdokumentvorlage, mit der Entwicklungsteams größere Änderungen vorschlagen können. Dieses gemeinsame Designdokument hilft uns, wichtige Änderungen an Google Cloud-Produkten einheitlich zu bewerten. Das folgende Diagramm zeigt unseren Standarddesignprozess für eine größere Änderung:

Detaillierte Darstellung der Schritte in der Designphase.

Die Designphase beginnt, wenn ein Softwareentwickler eine Änderung vorschlägt, die Geschäfts-, technische, Kosten- und Wartungsanforderungen anspricht. Nach dem Einreichen der Änderung beginnt ein umfassender Prüf- und Genehmigungsprozess durch erfahrene Experten, darunter Zuverlässigkeits- und Sicherheitsexperten sowie technische Prüfer. Die Implementierung der Änderung kann erst fortgesetzt werden, nachdem der Entwickler, der das Design vorgeschlagen hat, das gesamte Feedback der Experten berücksichtigt und jedes Mitglied des Expertenteams das Design genehmigt hat. Durch diesen Design- und Prüfprozess wird die Wahrscheinlichkeit verringert, dass Google Cloud-Produktteams überhaupt mit Änderungen beginnen, die sich negativ auf Kunden in der Produktion auswirken könnten.

Sicher wie entwickelt

Durch unseren Codeentwicklungsprozess wird die Qualität und Zuverlässigkeit unseres Codes verbessert. Nach der Genehmigung einer vorgeschlagenen Änderung beginnt der Entwicklungsvorgang mit einem umfassenden Onboarding für neue Entwickler, einschließlich Schulung, Mentoring und detailliertem Feedback zu vorgeschlagenen Codeänderungen. Der Code wird durch einen mehrschichtigen Entwicklungs- und Testansatz mit manuellen und automatisierten Tests in jeder Entwicklungsphase kontinuierlich validiert. Jede Codeänderung wird sorgfältig geprüft, um sicherzustellen, dass sie den hohen Standards von Google entspricht.

Das folgende Diagramm zeigt einen Workflow, der ungefähr den Ablauf unseres Entwicklungsprozesses darstellt:

Detaillierte Darstellung der Schritte in der Entwicklungsphase.

Die Entwicklungsphase beginnt, wenn ein Entwickler mit dem Schreiben von Code und entsprechenden Unit- und Integrationstests beginnt. Während dieser Phase kann der Entwickler von ihm geschriebene Tests und eine Reihe von Vorabtests ausführen, um sicherzustellen, dass Codeerweiterungen und -änderungen gültig sind. Nachdem der Entwickler die Codeänderungen abgeschlossen und Tests durchgeführt hat, bittet er eine andere, mit dem Code vertraute Person um eine manuelle Überprüfung. Dieser manuelle Überprüfungsprozess ist oft iterativ und kann zu zusätzlichen Codeüberarbeitungen führen. Wenn sich Autor und Prüfer einigen, reicht der Autor den Code ein.

Codierungsstandards sorgen für Änderungen von hoher Qualität

Die Entwicklungskultur, -praktiken und -tools von Google sind darauf ausgelegt, dass unser Code korrekt, klar, prägnant und effizient ist. Die Codeentwicklung bei Google findet in unserem Monorepo statt, dem weltweit größten integrierten Code-Repository. Das Monorepo enthält Millionen von Quelldateien, Milliarden von Codezeilen und eine Historie mit Hunderten Millionen Commits, die als Änderungslisten bezeichnet werden. Die Datenbank wächst weiter rasant. Es werden jeden Arbeitstag Zehntausende neuer Änderungslisten hinzugefügt. Zu den wichtigsten Vorteilen des Monorepos gehören die erleichterte Codewiederverwendung, die Vereinfachung des Abhängigkeitsmanagements und die Durchsetzung einheitlicher Entwicklerworkflows für Produkte und Dienste.

Die Codewiederverwendung ist hilfreich, da wir bereits eine gute Vorstellung davon haben, wie sich ein wiederverwendeter Code in der Produktion verhält. Durch die Verwendung von hochwertigem vorhandenen Code sind Änderungen von Natur aus robuster und einfacher im erforderlichen Standard zu pflegen. Dies spart nicht nur Zeit und Mühe, sondern sorgt auch dafür, dass die Codebasis insgesamt fehlerfrei bleibt, was zu zuverlässigeren Produkten führt.

Google Cloud-Dienste, die auf hochwertiger Open-Source-Software basieren, können das Monorepo durch ein weiteres Repository ergänzen – in der Regel Git –, um die Open-Source-Software über Verzweigungen zu verwalten.

Hinweis zum Training

Die Investition in die Codequalität beginnt, wenn ein Entwickler einem Team beitritt. Wenn ein Entwickler neu bei Google ist oder noch nicht ganz mit der Infrastruktur und Architektur des Teams vertraut ist, durchläuft er ein umfassendes Onboarding. Im Rahmen dieses Onboardings lernen sie Styleguides, Best Practices und Entwicklungsanleitungen kennen und führen manuelle praktische Übungen durch. Außerdem benötigen neue Entwickler eine zusätzliche Genehmigungsebene für jede einzelne Änderungsliste. Die Genehmigung für Änderungen in einer bestimmten Programmiersprache wird von Entwicklern erteilt, die aufgrund ihres Fachwissens strenge Prüfungen bestanden und sich in dieser Programmiersprache einen Ruf für Lesbarkeit erworben haben. Jeder Entwickler kann die Lesbarkeit für eine Programmiersprache erhalten. Die meisten Teams haben mehrere Genehmiger für die Programmiersprachen, in denen sie programmieren.

Shift-Left verbessert die Geschwindigkeit auf sichere Weise

Shift-Left ist ein Prinzip, bei dem Tests und Validierungen früher im Entwicklungsprozess erfolgen. Dieses Prinzip basiert auf unserer Beobachtung, dass die Kosten dramatisch steigen, je später im Release-Prozess wir einen Fehler finden und beheben. Nehmen wir einen extremen Fall an: ein Kunde findet einen Fehler in der Produktion. Dieser Fehler kann sich negativ auf die Arbeitslasten und Anwendungen des Kunden auswirken. Außerdem muss der Kunde möglicherweise den Cloud Customer Care-Prozess durchlaufen, bevor das zuständige Engineering-Team den Fehler beheben kann. Wenn der Entwickler, der mit der Behebung des Problems beauftragt ist, nicht die Person ist, die die Änderung vorgenommen hat, die den Fehler enthielt, muss er sich mit den Codeänderungen vertraut machen, wodurch wahrscheinlich mehr Zeit benötigt wird, um den Fehler zu reproduzieren und schließlich zu beheben. Dieser gesamte Prozess verbraucht viel Zeit von Kunden und dem Google Cloud-Support und erfordert, dass Entwickler ihre Arbeit unterbrechen, um ein Problem zu beheben.

Betrachten wir jetzt den Fall, dass ein Fehler bei einem automatischen Fehlertest erkannt wird, während ein Entwickler an einer Änderung arbeitet, die sich in der Entwicklung befindet. Wenn der Entwickler den Testfehler sieht, kann er ihn sofort beheben. Aufgrund unserer Codierungsstandards könnte der Entwickler die Änderung mit dem Testfehler nicht einmal einreichen. Durch diese frühzeitige Erkennung kann der Entwickler den Fehler beheben, ohne dass es Auswirkungen auf die Kunden gibt, und es gibt keinen zusätzlichen Aufwand durch Kontextwechsel.

Letzteres Szenario ist für alle Beteiligten unendlich vorzuziehen. Daher hat Google Cloud im Laufe der Jahre stark in dieses Prinzip investiert und Tests, die traditionell während der Qualifizierung und Einführung von Änderungen durchgeführt wurden, direkt in den Entwicklungszyklus verlagert. Heute werden alle Unit-Tests, alle bis auf die größten Integrationstests und umfangreiche statische und dynamische Analysen parallel ausgeführt, während ein Entwickler Codeänderungen vorschlägt.

Automatisierte Vorabtests erzwingen Codierungsstandards

Presubmit-Tests sind Prüfungen, die ausgeführt werden, bevor Änderungen in einem bestimmten Verzeichnis eingereicht werden. Vor der Einreichung können spezifische Unit- und Integrationstests für eine Änderung oder für alle Änderungen relevante, allgemeine Tests (z. B. statische und dynamische Analysen) ausgeführt werden. Bisher wurden Presubmit-Tests als allerletzter Schritt ausgeführt, bevor jemand eine Änderung an einer Codebasis einreichte. Heute führen wir – teilweise aufgrund des „Shift Left“-Prinzips und unserer CI-Implementierung – kontinuierlich Presubmit-Tests aus, während Entwickler Codeänderungen in einer Entwicklungsumgebung vornehmen und bevor sie die Änderungen in unser Monorepo einfügen. Entwickler können eine Test-Suite vor dem Einreichen auch manuell mit nur einem Klick in der Entwicklungs-UI auslösen. Tests vor dem Einreichen werden automatisch für jede Änderungsliste ausgeführt, bevor der Code manuell geprüft wird.

Die Test-Suite vor der Einreichung umfasst in der Regel Unit-Tests, Fuzz-Tests (Fuzzing), hermetische Integrationstests sowie statische und dynamische Codeanalysen. Bei Änderungen an Kernbibliotheken oder Code, der bei Google weit verbreitet ist, führen Entwickler einen globalen Presubmit durch. Bei einem globalen Presubmit-Test wird die Änderung an der gesamten Google-Codebasis getestet, um das Risiko zu minimieren, dass sich eine vorgeschlagene Änderung negativ auf andere Projekte oder Systeme auswirkt.

Unit- und Integrationstests

Umfassende Tests sind ein wesentlicher Bestandteil des Codeentwicklungsprozesses. Alle Mitarbeiter müssen Unit-Tests für Codeänderungen schreiben. Außerdem wird die Codeabdeckung auf Projektebene kontinuierlich erfasst, um sicherzustellen, dass erwartetes Verhalten validiert wird. Außerdem sind für wichtiges Nutzerverhalten Integrationstests erforderlich, bei denen die Funktionalität aller erforderlichen Komponenten und Abhängigkeiten geprüft wird.

Unittests und alle nicht übergroßen Integrationstests sind so konzipiert, dass sie schnell abgeschlossen werden. Sie werden inkrementell und mit hoher Parallelität in einer verteilten Umgebung ausgeführt, was zu schnellem und kontinuierlichem automatisiertem Entwicklungsfeedback führt.

Fuzzing

Während Unit- und Integrationstests uns dabei helfen, das erwartete Verhalten mit vordefinierten Eingaben und Ausgaben zu validieren, ist Fuzzing eine Technik, bei der eine Anwendung mit zufälligen Eingaben bombardiert wird, um versteckte Fehler oder Schwächen aufzudecken, die zu Sicherheitslücken oder Abstürzen führen können. Mithilfe des Fuzzing können wir potenzielle Schwachstellen in unserer Software proaktiv erkennen und beheben, um die allgemeine Sicherheit und Zuverlässigkeit unserer Produkte zu verbessern, bevor Kunden mit Änderungen interagieren. Die Zufälligkeit dieser Tests ist besonders nützlich, da Nutzer manchmal auf interessante, von uns so nicht erwartete Weise mit unseren Produkten interagieren. Mit Fuzzing können wir Szenarien berücksichtigen, die wir manuell nicht berücksichtigt haben.

Statische Analyse

Statische Analysetools spielen eine wichtige Rolle bei der Aufrechterhaltung der Codequalität in unseren Entwicklungsabläufen. Die statische Analyse hat sich seit den ersten Lint-Versuchen mit regulären Ausdrücken zur Identifizierung problematischer C++-Codemuster erheblich weiterentwickelt. Die statische Analyse deckt derzeit alle Google Cloud-Produktionssprachen ab und findet fehlerhafte, ineffiziente oder veraltete Codemuster.

Mit erweiterten Compiler-Frontends und LLMs können wir automatisch Verbesserungen vorschlagen, während Entwickler Code schreiben. Jede vorgeschlagene Codeänderung wird über statische Analysen geprüft. Während wir im Laufe der Zeit neue statische Prüfungen hinzufügen, wird der gesamte Codebestand ständig auf Einhaltung der Anforderungen geprüft. Fehlerbehebungen werden automatisch generiert und zur Prüfung eingereicht.

Dynamische Analyse

Während sich die statische Analyse darauf konzentriert, bekannte Codemuster zu identifizieren, die zu Problemen führen können, verfolgt die dynamische Analyse einen anderen Ansatz. Dabei wird Code kompiliert und ausgeführt, um Probleme zu finden, die sich erst bei der Ausführung zeigen, z. B. Speicherverletzungen und Race-Bedingungen. Google nutzt seit vielen Jahren dynamische Analysen und hat sogar einige Tools mit der breiteren Entwicklercommunity geteilt, darunter:

  • AddressSanitizer: Erkennt Arbeitsspeicherfehler wie Überläufe des Zwischenspeichers und Use-After-Free
  • ThreadSanitizer (C++, Go): Erkennt Data Races und andere Fehler im Thread.
  • MemorySanitizer: Ermöglicht die Erkennung nicht initialisierter Arbeitsspeichernutzung

Diese und ähnliche Tools sind unerlässlich, um komplexe Fehler zu finden, die nicht nur durch statische Analyse erkannt werden können. Durch die Verwendung sowohl statischer als auch dynamischer Analysen möchte Google dafür sorgen, dass der Code gut strukturiert ist, keine bekannten Probleme aufweist und sich in realen Szenarien wie erwartet verhält.

Änderungen und Testergebnisse durch manuelle Code Reviews validieren

Wenn ein Entwickler einen wichtigen Meilenstein in seinem Code erreicht und ihn in das Haupt-Repository einbinden möchte, löst er eine Code Review aus, indem er eine Änderungsliste vorschlägt. Ein Antrag auf eine Code Review besteht aus folgenden Elementen:

  • Eine Beschreibung, die den Zweck der Änderungen und zusätzlichen Kontext enthält
  • Der tatsächlich geänderte Code
  • Unit- und Integrationstests für den geänderten Code
  • Ergebnisse der automatisierten Vorabtests

An dieser Stelle des Entwicklungsprozesses kommt ein weiterer Mensch ins Spiel. Ein oder mehrere benannte Prüfer prüfen die Änderungsliste sorgfältig auf Richtigkeit und Klarheit. Dabei nutzen sie die angehängten Tests und die Ergebnisse vor der Einreichung als Leitfaden. Für jedes Codeverzeichnis sind Prüfer verantwortlich, die für die Qualität dieses Teils der Codebasis sorgen. Ihre Genehmigung ist erforderlich, um Änderungen im relevanten Verzeichnis vorzunehmen. Prüfer und Entwickler arbeiten zusammen, um Probleme zu erkennen und zu beheben, die durch eine vorgeschlagene Codeänderung auftreten könnten. Wenn die Änderungsliste unseren Standards entspricht, gibt ein Prüfer seine Genehmigung („LGTM“, kurz für „Looks Good to Me“, d. h. „Sieht gut aus“). Wenn der Entwickler jedoch für die verwendete Programmiersprache noch geschult wird, benötigt er eine zusätzliche Genehmigung von einem Experten, der sich mit der Programmiersprache auskennt.

Nachdem eine Änderungsliste die Tests und automatisierten Prüfungen bestanden und eine LGTM-Benachrichtigung erhalten hat, darf der Entwickler, der die Änderung vorgeschlagen hat, nun minimale Änderungen am Code vornehmen. Alle wesentlichen Änderungen machen Genehmigungen ungültig und erfordern eine weitere Prüfung. Selbst kleine Änderungen werden den ursprünglichen Prüfern automatisch gemeldet. Sobald der Entwickler den bearbeiteten Code eingereicht hat, wird er noch einmal vor dem Einreichen getestet, bevor die Änderungsliste in das Monorepo aufgenommen wird. Wenn Tests fehlschlagen, wird die Einreichung abgelehnt und der Entwickler und die Prüfer werden aufgefordert, Korrekturmaßnahmen zu ergreifen, bevor sie versuchen, die Änderungen noch einmal einzureichen.

Zertifizierung für die sichere Freigabe

Die Tests vor der Einreichung sind zwar umfassend, aber nicht das Ende des Testprozesses bei Google. Teams haben oft zusätzliche Tests, z. B. groß angelegte Integrationstests, die während der ersten Code Review nicht ausgeführt werden können. Sie können länger dauern oder High-Fidelity-Testumgebungen erfordern. Außerdem müssen Teams auf Fehler achten, die durch Faktoren verursacht werden, auf die sie keinen Einfluss haben, z. B. Änderungen an externen Abhängigkeiten.

Aus diesem Grund ist nach der Entwicklungsphase eine Qualifizierungsphase erforderlich. In dieser Qualifikationsphase wird ein kontinuierlicher Build- und Testprozess verwendet, wie im folgenden Diagramm dargestellt:

Detaillierte Darstellung der Schritte der Qualifikationsphase.

In dieser Phase werden regelmäßig Tests für den gesamten Code ausgeführt, der seit dem letzten Durchlauf direkt oder indirekt geändert wurde. Alle Fehler werden automatisch an das zuständige Engineering-Team weitergeleitet. In vielen Fällen kann das System die Änderungsliste, die den Fehler verursacht hat, automatisch identifizieren und rückgängig machen. Diese groß angelegten Integrationstests werden in einer Vielzahl von Staging-Umgebungen durchgeführt, von teilweise simulierten Umgebungen bis hin zu ganzen physischen Standorten.

Tests haben eine Vielzahl von Qualifikationszielen, die von grundlegender Zuverlässigkeit und Sicherheit bis hin zur Geschäftslogik reichen. Diese Qualifikationstests umfassen Tests des Codes auf folgende Elemente:

  • Die Fähigkeit, die erforderlichen Funktionen bereitzustellen, was mithilfe von groß angelegten Integrationstests getestet wird
  • Die Fähigkeit, Geschäftsanforderungen zu erfüllen, wird mit synthetischen Darstellungen von Kundenlasten getestet
  • Die Fähigkeit, Ausfälle der zugrunde liegenden Infrastruktur zu verkraften, was durch das Einschleusen von Fehlern in den gesamten Stack getestet wird
  • Die Fähigkeit, die Bereitstellungskapazität aufrechtzuerhalten, was mit Lasttest-Frameworks getestet wird
  • Möglichkeit zum sicheren Rollback

Sichere Einführungen

Selbst bei den besten Entwicklungs-, Test- und Qualifizierungsprozessen schleichen sich manchmal Fehler in Produktionsumgebungen ein, die sich negativ auf unsere Nutzer auswirken. In diesem Abschnitt wird erläutert, wie der Google Cloud-Bereitstellungsprozess die Auswirkungen fehlerhafter Änderungen begrenzt und eine schnelle Erkennung von REgressionen ermöglicht. Wir wenden diesen Ansatz auf alle Arten von Änderungen an, die in der Produktion bereitgestellt werden, darunter Binärdateien, Konfigurationen, Schemaupdates, Kapazitätsänderungen und Listen zur Zugriffssteuerung.

Änderungsübertragung und -überwachung

Wir wenden einen einheitlichen Ansatz für die Bereitstellung von Änderungen in Google Cloud an, um negative Auswirkungen auf Kunden zu minimieren und Probleme auf einzelne logische und physische Fehlerbereiche zu begrenzen. Der Prozess nutzt unsere über Jahrzehnte entwickelten SRE-Reliabilitätspraktiken und unserem Monitoringsystem auf Planetenebene, um schädliche Änderungen so schnell wie möglich zu erkennen und zu beheben. Durch die schnelle Erkennung können wir Kunden schneller benachrichtigen und Korrekturmaßnahmen ergreifen, um ähnliche Fehler systematisch zu vermeiden.

Die meisten Google Cloud-Produkte sind regional oder zonal. Das bedeutet, dass ein regionales Produkt, das in Region A ausgeführt wird, unabhängig von demselben Produkt ist, das in Region B ausgeführt wird. Ebenso ist ein zonales Produkt, das in Zone C in Region A ausgeführt wird, unabhängig von demselben zonalen Produkt, das in Zone D in Region A ausgeführt wird. Diese Architektur minimiert das Risiko eines Ausfalls, der sich auf andere Regionen oder andere Zonen innerhalb einer Region auswirkt. Einige Dienste, darunter IAM und die Google Cloud Console, bieten eine global einheitliche Ebene, die alle Regionen umfasst. Deshalb nennen wir sie globale Dienste. Globale Dienste werden in Regionen repliziert, um Single Points of Failure zu vermeiden und die Latenz zu minimieren. Die gemeinsame Google Cloud-Roll-out-Plattform weiß, ob ein Dienst zonal, regional oder global ist, und orchestriert Produktionsänderungen entsprechend.

Beim Google Cloud-Roll-out werden alle Repliken eines Dienstes, der an mehreren Zielstandorten bereitgestellt wird, in Wellen aufgeteilt. Die ersten Wellen umfassen eine kleine Anzahl an Replicas, wobei die Updates seriell ablaufen. Bei den ersten Wellen werden die meisten Kundenarbeitslasten durch eine maximierte Vielfalt der Arbeitslasten geschützt, sodass Probleme so früh wie möglich erkannt werden. Außerdem werden synthetische Arbeitslasten verwendet, die gängige Muster von Kundenarbeitslasten nachahmen.

Wenn das Roll-out weiterhin erfolgreich ist, während Dienstrepliken an den Zielstandorten aktualisiert werden, werden nachfolgende Roll-out-Wellen nach und nach größer und es wird mehr Parallelität eingeführt. Auch wenn ein gewisser Parallelismus erforderlich ist, um die Anzahl der Google Cloud-Standorte zu berücksichtigen, sind gleichzeitige Updates für Standorte in verschiedenen Wellen nicht zulässig. Wenn eine Welle in die Nacht oder ein Wochenende hineinreicht, kann sie abgeschlossen werden. Eine neue Welle kann jedoch erst zu Beginn der Geschäftszeiten des Teams gestartet werden, das das Roll-out verwaltet.

Das folgende Diagramm ist ein Beispiel für einen Workflow, der die Roll-out-Logik veranschaulicht, die wir in Google Cloud für regionale Produkte und Dienste verwenden:

Detailliertes Diagramm der Schritte in der Einführungsphase.

Beim Google Cloud-Roll-out wird der Canary Analysis Service (CAS) verwendet, um A/B-Tests während des gesamten Roll-outs zu automatisieren. Einige Replikats werden zu Canarys (d. h. eine teilweise und zeitlich begrenzte Bereitstellung einer Änderung in einem Dienst). Die verbleibenden Replikats bilden die Kontrollgruppe, die die Änderung nicht enthält. Jeder Schritt des Roll-out-Prozesses nutzt eine Wartezeit, um Probleme zu erkennen, die sich erst mit der Zeit zeigen, bevor mit dem nächsten Schritt fortgefahren wird. So wird sichergestellt, dass alle Funktionen eines Dienstes gut getestet und potenzielle Anomalien von CAS erkannt werden. Die Auslagerungszeit wird sorgfältig festgelegt, um die Erkennung von Problemen mit langsamem Verlauf mit der Entwicklungsgeschwindigkeit in Einklang zu bringen. Google Cloud-Roll-outs dauern in der Regel eine Woche.

Dieses Diagramm bietet einen schnellen Überblick über den CAS-Workflow:

Diagramm der Schritte im CAS-Workflow.

Der Workflow beginnt damit, dass das Roll-out-Tool die Änderung auf dem Canary-Replikat implementiert. Das Roll-out-Tool fordert dann ein Urteil von CAS an. CAS vergleicht das Canary-Replikat mit der Kontrollgruppe und gibt als Ergebnis „PASS“ oder „FAIL“ zurück. Wenn ein Systemstatussignal fehlschlägt, wird eine Benachrichtigung für die Dienstinhaber generiert und der laufende Schritt des Roll-outs wird angehalten oder rückgängig gemacht. Wenn die Änderung zu Unterbrechungen für externe Kunden führt, wird ein externer Vorfall erklärt und die betroffenen Kunden werden über den Personalized Service Health-Dienst benachrichtigt. Vorfälle lösen auch eine interne Prüfung aus. Die Postmortem-Philosophie von Google sorgt dafür, dass die richtigen Korrekturmaßnahmen identifiziert und angewendet werden, um die Wahrscheinlichkeit zu minimieren, dass ähnliche Fehler noch einmal auftreten.

Signale für die Überwachung und Sicherheit nach der Einführung

Softwarefehler treten nicht immer sofort auf. Einige erfordern möglicherweise bestimmte Umstände, um ausgelöst zu werden. Aus diesem Grund überwachen wir die Produktionssysteme auch nach Abschluss eines Roll-outs weiter. Im Laufe der Jahre haben wir festgestellt, dass ein fehlerhaftes Roll-out, selbst wenn es nicht sofort Probleme auslöst, immer noch die wahrscheinlichste Ursache für einen Produktionsvorfall ist. Aus diesem Grund werden die Incident Responder in unseren Produktions-Playbooks angewiesen, kürzliche Roll-outs mit den beobachteten Problemen in Verbindung zu bringen und standardmäßig ein neueres Roll-out rückgängig zu machen, wenn aktuelle Änderungen nicht als Grund für den Vorfall ausgeschlossen werden können.

Das Monitoring nach dem Roll-out basiert auf denselben Monitoring-Signalen, die wir für automatisierte A/B-Tests während eines Roll-out-Zeitraums verwenden. Die Google Cloud-Philosophie für Monitoring und Benachrichtigungen kombiniert zwei Arten von Monitoring: Introspektives Monitoring (auch White-Box-Monitoring genannt) und Synthetisches Monitoring (auch Black-Box-Monitoring genannt). Beim introspektiven Monitoring werden Messwerte wie CPU-Auslastung, Speicherauslastung und andere interne Dienstdaten verwendet. Beim synthetischen Monitoring wird das Systemverhalten aus der Perspektive eines Kunden betrachtet. Dabei werden Dienstfehlerraten und Reaktionen auf synthetischen Traffic von Prüfdiensten erfasst. Beim synthetischen Monitoring werden Symptome erfasst und aktive Probleme identifiziert. Mit dem introspektiven Monitoring können wir bestätigte Probleme diagnostizieren und in einigen Fällen bevorstehende Probleme erkennen.

Um Vorfälle zu erkennen, die nur einige Kunden betreffen, gruppieren wir Kundenarbeitslasten in Kohorten ähnlicher Arbeitslasten. Benachrichtigungen werden ausgelöst, sobald die Leistung einer Kohorte von der Norm abweicht. Anhand dieser Benachrichtigungen können wir kundenspezifische Regressionen erkennen, auch wenn die Gesamtleistung normal erscheint.

Schutz der Softwarelieferkette

Wenn Google Cloud-Teams Änderungen vornehmen, verwenden wir eine Sicherheitsprüfung namens Binary Authorization for Borg (BAB), um unsere Softwarelieferkette und Cloud-Kunden vor Insiderrisiken zu schützen. BAB beginnt in der Phase der Code review und erstellt einen Audit-Trail für Code und Konfiguration, die in der Produktion bereitgestellt werden. Um die Integrität der Produktion zu sichern, sind nur Änderungen zulässig, die die folgenden Kriterien erfüllen:

  • Sie sind manipulationssicher und signiert.
  • Stammen von einem identifizierten Build-Partner und einem identifizierten Quellstandort
  • Wurden von einer anderen Person als dem Codeautor geprüft und ausdrücklich genehmigt

Falls Sie einige dieser Konzepte in Ihrem eigenen Softwareentwicklungszyklus anwenden möchten, haben wir wichtige BAB-Konzepte in eine offene Spezifikation namens Supply Chain Levels for Software Artifacts (SLSA) aufgenommen. Das SLSA dient als Sicherheitsframework für die Entwicklung und Ausführung von Code in Produktionsumgebungen.

Fazit

Google Cloud baut auf den jahrzehntelangen Investitionen von Google in die Entwicklung von Spitzentechnologien auf. Codequalität und Produktionsqualität sind kulturelle Grundsätze, die allen Entwicklungsteams bei Google vermittelt werden. Bei unserem Design-Prüfprozess werden die Auswirkungen auf den Code und die Produktionsintegrität frühzeitig berücksichtigt. Unser Entwicklungsvorgang, der auf dem „Shift-Left“-Prinzip und umfangreichen Tests basiert, sorgt dafür, dass Designideen sicher und korrekt implementiert werden. Unser Qualifizierungsprozess erweitert die Tests, um groß angelegte Integrationen und externe Abhängigkeiten abzudecken. Schließlich können wir mit unserer Einführungsplattform nach und nach die Gewissheit gewinnen, dass sich eine bestimmte Änderung tatsächlich wie erwartet verhält. Mit unserem Ansatz können wir von der Konzeption bis zur Produktion die Erwartungen von Google Cloud-Kunden sowohl in Bezug auf die Entwicklungsgeschwindigkeit als auch die Zuverlässigkeit erfüllen.