Dieses Prinzip in der Säule „Nachhaltigkeit“ des Google Cloud Well-Architected Framework enthält Empfehlungen zum Schreiben von Software, die den Energieverbrauch und die Serverlast minimiert.
Übersicht über die Grundsätze
Wenn Sie Best Practices zum Erstellen Ihrer Cloud-Anwendungen befolgen, optimieren Sie die Energie, die von den Cloud-Infrastrukturressourcen genutzt wird: KI, Computing, Speicher und Netzwerk. Außerdem tragen Sie dazu bei, den Wasserbedarf der Rechenzentren und den Energieverbrauch der Endnutzergeräte beim Zugriff auf Ihre Anwendungen zu senken.
Um energieeffiziente Software zu entwickeln, müssen Sie Nachhaltigkeitsaspekte in den gesamten Softwarelebenszyklus integrieren, vom Design und der Entwicklung über die Bereitstellung und Wartung bis hin zur Archivierung. Eine detaillierte Anleitung zur Verwendung von KI zum Entwickeln von Software, die die Umweltauswirkungen von Cloud-Arbeitslasten minimiert, finden Sie im Google Cloud E-Book Build Software Sustainably.
Empfehlungen
Die Empfehlungen in diesem Abschnitt sind in die folgenden Schwerpunktbereiche unterteilt:
- Rechenaufwand minimieren: Verwenden Sie schlanken, fokussierten Code, der redundante Logik vermeidet und unnötige Berechnungen oder Funktionsüberfrachtung verhindert.
- Effiziente Algorithmen und Datenstrukturen verwenden: Wählen Sie zeiteffiziente und speichereffiziente Algorithmen aus, die die CPU-Last reduzieren und die Arbeitsspeichernutzung minimieren.
- Compute- und Datenvorgänge optimieren: Entwickeln Sie mit dem Ziel, alle verfügbaren Ressourcen effizient zu nutzen, einschließlich CPU, Arbeitsspeicher, Laufwerk-E/A und Netzwerk. Wenn Sie beispielsweise Busy-Loops durch ereignisgesteuerte Logik ersetzen, vermeiden Sie unnötiges Polling.
- Frontend-Optimierung implementieren: Um den Stromverbrauch von Endnutzergeräten zu senken, sollten Sie Strategien wie Minimierung, Komprimierung und Lazy Loading für Bilder und Assets verwenden.
Rechenaufwand minimieren
Um energieeffiziente Software zu schreiben, müssen Sie die Gesamtzahl der Rechenvorgänge, die Ihre Anwendung ausführt, minimieren. Jede unnötige Anweisung, jede redundante Schleife und jede zusätzliche Funktion verbraucht Energie, Zeit und Ressourcen. Mit den folgenden Empfehlungen können Sie Software entwickeln, die nur minimale Berechnungen ausführt.
Schlanken, fokussierten Code schreiben
Um nur den Code zu schreiben, der für die gewünschten Ergebnisse erforderlich ist, können Sie so vorgehen:
- Redundante Logik und Funktionsüberfrachtung vermeiden: Schreiben Sie Code, der nur die wesentlichen Funktionen ausführt. Vermeiden Sie Funktionen, die den Rechenaufwand und die Komplexität erhöhen, aber Ihren Nutzern keinen messbaren Mehrwert bieten.
- Refaktorieren: Um die Energieeffizienz im Laufe der Zeit zu verbessern, sollten Sie Ihre Anwendungen regelmäßig prüfen, um ungenutzte Funktionen zu identifizieren. Ergreifen Sie Maßnahmen, um solche Funktionen nach Bedarf zu entfernen oder umzugestalten.
- Unnötige Vorgänge vermeiden: Berechnen Sie einen Wert oder führen Sie eine Aktion erst aus, wenn das Ergebnis benötigt wird. Verwenden Sie Techniken wie die verzögerte Auswertung, bei der Berechnungen erst dann ausgeführt werden, wenn eine abhängige Komponente in der Anwendung die Ausgabe benötigt.
- Lesbarkeit und Wiederverwendbarkeit von Code priorisieren: Schreiben Sie Code, der lesbar und wiederverwendbar ist. Dieser Ansatz minimiert Duplikate und folgt dem DRY-Prinzip (Don't Repeat Yourself), das dazu beitragen kann, die CO2-Emissionen bei der Softwareentwicklung und ‑wartung zu reduzieren.
Backend-Caching verwenden
Durch Backend-Caching wird sichergestellt, dass eine Anwendung nicht wiederholt dieselben Aufgaben ausführt. Eine hohe Cache-Trefferquote führt zu einer fast linearen Reduzierung des Energieverbrauchs pro Anfrage. Verwenden Sie die folgenden Techniken, um das Backend-Caching zu implementieren:
- Häufig verwendete Daten im Cache speichern: Speichern Sie häufig verwendete Daten an einem temporären, leistungsstarken Speicherort. Verwenden Sie beispielsweise einen In-Memory-Caching-Dienst wie Memorystore. Wenn eine Anwendung Daten aus einem Cache abruft, wird die Anzahl der Datenbankabfragen und Datenträger-E/A-Vorgänge reduziert. Dadurch wird die Last auf die Datenbanken und Server im Backend verringert.
- API-Antworten im Cache speichern: Um redundante und kostspielige Netzwerkaufrufe zu vermeiden, sollten Sie die Ergebnisse häufiger API-Anfragen im Cache speichern.
- In-Memory-Caching priorisieren: Um langsame Festplatten-E/A-Vorgänge und komplexe Datenbankabfragen zu vermeiden, sollten Sie Daten im schnellen Arbeitsspeicher (RAM) speichern.
- Wählen Sie geeignete Cache-Schreibstrategien aus.:
- Die Write-Through-Strategie sorgt dafür, dass Daten synchron in den Cache und den persistenten Speicher geschrieben werden. Diese Strategie erhöht die Wahrscheinlichkeit von Cache-Treffern, sodass der persistente Speicher weniger energieintensive Leseanfragen erhält.
- Die Write-Back-Strategie (Write-Behind) verbessert die Leistung von schreibintensiven Anwendungen. Daten werden zuerst in den Cache geschrieben und die Datenbank wird später asynchron aktualisiert. Diese Strategie reduziert die unmittelbare Schreiblast auf langsameren Datenbanken.
- Intelligente Richtlinien zum Entfernen verwenden: Halten Sie den Cache schlank und effizient. Um veraltete oder wenig genutzte Daten zu entfernen und den für häufig angeforderte Daten verfügbaren Speicherplatz zu maximieren, verwenden Sie Richtlinien wie Gültigkeitsdauer (TTL), zuletzt verwendet (LRU) und am wenigsten verwendet (LFU).
Effiziente Algorithmen und Datenstrukturen verwenden
Die von Ihnen ausgewählten Algorithmen und Datenstrukturen bestimmen die rohe Rechenkomplexität Ihrer Software. Wenn Sie geeignete Algorithmen und Datenstrukturen auswählen, minimieren Sie die Anzahl der CPU-Zyklen und Speichervorgänge, die zum Ausführen einer Aufgabe erforderlich sind. Weniger CPU-Zyklen und Arbeitsspeicheroperationen führen zu einem geringeren Energieverbrauch.
Algorithmen für optimale Zeitkomplexität auswählen
Priorisieren Sie Algorithmen, die das erforderliche Ergebnis in der kürzesten Zeit erzielen. So lässt sich die Dauer der Ressourcennutzung verkürzen. So wählen Sie Algorithmen aus, die die Ressourcennutzung optimieren:
- Komplexität reduzieren: Um die Komplexität zu bewerten, sollten Sie nicht nur Laufzeitmesswerte, sondern auch die theoretische Komplexität des Algorithmus berücksichtigen. Im Vergleich zum Bubblesort reduziert Mergesort beispielsweise den Rechenaufwand und den Energieverbrauch für große Datasets erheblich.
- Redundante Arbeit vermeiden: Verwenden Sie integrierte, optimierte Funktionen in der von Ihnen gewählten Programmiersprache oder dem Framework. Diese Funktionen werden oft in einer Low-Level- und energieeffizienteren Sprache wie C oder C++ implementiert. Sie sind also besser für die zugrunde liegende Hardware optimiert als benutzerdefinierte Funktionen.
Datenstrukturen für Effizienz auswählen
Die von Ihnen ausgewählten Datenstrukturen bestimmen, wie schnell Daten abgerufen, eingefügt oder verarbeitet werden können. Diese Geschwindigkeit wirkt sich auf die CPU- und Arbeitsspeichernutzung aus. So wählen Sie effiziente Datenstrukturen aus:
- Für Suche und Abruf optimieren: Verwenden Sie für häufige Vorgänge wie das Prüfen, ob ein Element vorhanden ist, oder das Abrufen eines bestimmten Werts Datenstrukturen, die für Geschwindigkeit optimiert sind. Hashmaps oder Hashsets ermöglichen beispielsweise Suchvorgänge in nahezu konstanter Zeit, was energieeffizienter ist als die lineare Suche in einem Array.
- Arbeitsspeicherbedarf minimieren: Effiziente Datenstrukturen tragen dazu bei, den gesamten Arbeitsspeicherbedarf einer Anwendung zu reduzieren. Durch den geringeren Arbeitsspeicherzugriff und die geringere Arbeitsspeicherverwaltung wird der Stromverbrauch gesenkt. Außerdem können Prozesse mit einem schlankeren Speicherprofil effizienter ausgeführt werden, sodass Sie Ressourcenupgrades aufschieben können.
- Spezialisierte Strukturen verwenden: Verwenden Sie Datenstrukturen, die speziell für ein bestimmtes Problem entwickelt wurden. Verwenden Sie beispielsweise eine Trie-Datenstruktur für die schnelle Suche nach Stringpräfixen und eine Prioritätswarteschlange, wenn Sie effizient nur auf den höchsten oder niedrigsten Wert zugreifen müssen.
Compute- und Datenvorgänge optimieren
Achten Sie bei der Softwareentwicklung auf eine effiziente und angemessene Ressourcennutzung im gesamten Technologie-Stack. Behandeln Sie CPU, Arbeitsspeicher, Festplatte und Netzwerk als begrenzte und gemeinsam genutzte Ressourcen. Erkennen Sie, dass eine effiziente Nutzung von Ressourcen zu spürbaren Senkungen der Kosten und des Energieverbrauchs führt.
CPU-Auslastung und Leerlaufzeit optimieren
Um die Zeit zu minimieren, die die CPU in einem aktiven, energieverbrauchenden Zustand verbringt, ohne sinnvolle Arbeit zu verrichten, können Sie die folgenden Ansätze verwenden:
- Ereignisgesteuerte Logik gegenüber Polling bevorzugen: Ersetzen Sie ressourcenintensive Busy-Loops oder konstantes Prüfen (Polling) durch ereignisgesteuerte Logik. Eine ereignisgesteuerte Architektur sorgt dafür, dass die Komponenten einer Anwendung nur dann ausgeführt werden, wenn sie durch relevante Ereignisse ausgelöst werden. Dieser Ansatz ermöglicht die Verarbeitung auf Abruf, wodurch ressourcenintensive Abrufe entfallen.
- Konstant hohe Frequenz verhindern: Schreiben Sie Code, der die CPU nicht zwingt, ständig mit der höchsten Frequenz zu arbeiten. Um den Energieverbrauch zu minimieren, sollten Systeme, die sich im Leerlauf befinden, in den Energiesparmodus oder in den Ruhemodus wechseln können.
- Asynchrone Verarbeitung verwenden: Verwenden Sie die asynchrone Verarbeitung, um zu verhindern, dass Threads während Leerlaufzeiten gesperrt werden. Dieser Ansatz setzt Ressourcen frei und führt zu einer höheren Gesamtressourcennutzung.
Speicher und Laufwerk-E/A effizient verwalten
Eine ineffiziente Arbeitsspeicher- und Laufwerksnutzung führt zu unnötiger Verarbeitung und einem erhöhten Stromverbrauch. Verwenden Sie die folgenden Techniken, um Arbeitsspeicher und E/A effizient zu verwalten:
- Strenge Speicherverwaltung: Ergreifen Sie Maßnahmen, um nicht verwendete Speicherressourcen proaktiv freizugeben. Vermeiden Sie es, große Objekte länger als nötig im Arbeitsspeicher zu halten. Dieser Ansatz verhindert Leistungsengpässe und reduziert den Stromverbrauch für den Speicherzugriff.
- Laufwerk-E/A optimieren: Reduzieren Sie die Häufigkeit der Lese- und Schreibvorgänge Ihrer Anwendung auf Ressourcen für nichtflüchtigen Speicher. Verwenden Sie beispielsweise einen Zwischenspeicherpuffer zum Speichern von Daten. Schreiben Sie die Daten in festen Intervallen oder wenn der Puffer eine bestimmte Größe erreicht in den nichtflüchtigen Speicher.
- Batchvorgänge: Fassen Sie häufige, kleine Laufwerkvorgänge in weniger, größeren Batchvorgängen zusammen. Ein Batchvorgang verbraucht weniger Energie als viele einzelne, kleine Transaktionen.
- Komprimierung verwenden: Reduzieren Sie die Menge der Daten, die auf Festplatten geschrieben oder von Festplatten gelesen werden, indem Sie geeignete Datenkomprimierungstechniken anwenden. Wenn Sie beispielsweise Daten komprimieren möchten, die Sie in Cloud Storage speichern, können Sie dekompressives Transcodieren verwenden.
Netzwerktraffic minimieren
Netzwerkressourcen verbrauchen bei der Datenübertragung viel Energie. Verwenden Sie die folgenden Techniken, um die Netzwerkkommunikation zu optimieren:
- Nutzlastgröße minimieren: Entwickeln Sie Ihre APIs und Anwendungen so, dass nur die für eine Anfrage erforderlichen Daten übertragen werden. Vermeiden Sie das Abrufen oder Zurückgeben großer JSON- oder XML-Strukturen, wenn nur wenige Felder erforderlich sind. Achten Sie darauf, dass die zurückgegebenen Datenstrukturen prägnant sind.
- Roundtrips reduzieren: Verwenden Sie intelligentere Protokolle, um die Anzahl der Netzwerk-Roundtrips zu reduzieren, die zum Ausführen einer Nutzeraktion erforderlich sind. Verwenden Sie beispielsweise HTTP/3 anstelle von HTTP/1.1, GraphQL anstelle von REST, binäre Protokolle und fassen Sie API-Aufrufe zusammen. Wenn Sie die Anzahl der Netzwerkaufrufe reduzieren, senken Sie den Energieverbrauch sowohl für Ihre Server als auch für die Geräte der Endnutzer.
Frontend-Optimierung implementieren
Durch die Frontend-Optimierung wird die Datenmenge minimiert, die Ihre Endnutzer herunterladen und verarbeiten müssen. Dadurch wird die Belastung der Ressourcen von Endnutzergeräten verringert.
Code und Assets minimieren
Wenn Endnutzer kleinere und effizienter strukturierte Ressourcen herunterladen und verarbeiten müssen, verbrauchen ihre Geräte weniger Strom. Um das Downloadvolumen und die Verarbeitungslast auf Endnutzergeräten zu minimieren, können Sie die folgenden Techniken verwenden:
- Minimierung und Komprimierung: Entfernen Sie bei JavaScript-, CSS- und HTML-Dateien unnötige Zeichen wie Leerzeichen und Kommentare mit geeigneten Minimierungstools. Achten Sie darauf, dass Dateien wie Bilder komprimiert und optimiert sind. Sie können die Minimierung und Komprimierung von Web-Assets mit einer CI/CD-Pipeline automatisieren.
- Lazy Loading: Bilder, Videos und nicht kritische Assets werden erst geladen, wenn sie tatsächlich benötigt werden, z. B. wenn diese Elemente in den sichtbaren Bereich einer Webseite gescrollt werden. Dieser Ansatz reduziert das Volumen des ersten Datentransfers und die Verarbeitungslast auf Endnutzergeräten.
- Kleinere JavaScript-Bundles: Entfernen Sie nicht verwendeten Code aus Ihren JavaScript-Bundles, indem Sie moderne Modul-Bundler und Techniken wie Tree Shaking verwenden. So entstehen kleinere Dateien, die schneller geladen werden und weniger Serverressourcen verbrauchen.
- Browser-Caching: Verwenden Sie HTTP-Caching-Header, um den Browser des Nutzers anzuweisen, statische Assets lokal zu speichern. Browser-Caching trägt dazu bei, dass bei nachfolgenden Besuchen wiederholte Downloads und unnötiger Netzwerkverkehr vermieden werden.
Leichte Benutzeroberfläche (UX) priorisieren
Das Design Ihrer Benutzeroberfläche kann sich erheblich auf die Rechenkomplexität für das Rendern von Frontend-Inhalten auswirken. Verwenden Sie die folgenden Techniken, um Front-End-Oberflächen mit einer einfachen Benutzeroberfläche zu erstellen:
- Effizientes Rendern: Vermeiden Sie ressourcenintensive, häufige DOM-Manipulationen (Document Object Model). Schreiben Sie Code, der die Rendering-Komplexität minimiert und unnötiges erneutes Rendern vermeidet.
- Leichte Designmuster: Verwenden Sie nach Möglichkeit statische Websites oder progressive Web-Apps (PWAs). Solche Websites und Apps werden schneller geladen und benötigen weniger Serverressourcen.
- Barrierefreiheit und Leistung: Responsive Websites, die schnell geladen werden, sind oft nachhaltiger und barrierefreier. Ein optimiertes, übersichtliches Design reduziert die Ressourcen, die beim Rendern von Inhalten verbraucht werden. Websites, die für Leistung und Geschwindigkeit optimiert sind, können zu höheren Umsätzen führen. Laut der Studie Milliseconds Make Millions von Deloitte und Google führt eine um 0,1 Sekunden (100 ms) verbesserte Websitegeschwindigkeit zu einer Steigerung der Conversion-Raten um 8,4 % bei Einzelhandelswebsites und zu einer Steigerung des durchschnittlichen Bestellwerts um 9,2 %.