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.
Prinzipübersicht
Wenn Sie Best Practices zum Erstellen Ihrer Cloud-Anwendungen befolgen, optimieren Sie die Energie, die von den Ressourcen der Cloud-Infrastruktur genutzt wird: KI, Computing, Speicher und Netzwerk. Außerdem tragen Sie dazu bei, den Wasserbedarf der Rechenzentren und den Energieverbrauch der Endnutzergeräte zu senken, wenn diese auf Ihre Anwendungen zugreifen.
Um energieeffiziente Software zu entwickeln, müssen Sie Nachhaltigkeitsaspekte in den gesamten Softwarelebenszyklus integrieren, von Design und Entwicklung bis hin zu Bereitstellung, Wartung und Archivierung. Eine detaillierte Anleitung zur Verwendung von KI zum Erstellen von Software, die die Umweltauswirkungen von Cloud-Arbeitslasten minimiert, finden Sie im E‑Book Google Cloud , Build Software Sustainably.
Empfehlungen
Die Empfehlungen in diesem Abschnitt sind in die folgenden Schwerpunkte unterteilt:
- Rechenaufwand minimieren: Bevorzugen Sie schlanken, fokussierten Code, der redundante Logik vermeidet und unnötige Berechnungen oder Feature-Bloat verhindert.
- Effiziente Algorithmen und Datenstrukturen verwenden: Wählen Sie zeiteffiziente und speichereffiziente Algorithmen aus, die die CPU-Last reduzieren und die Arbeitsspeichernutzung minimieren.
- Computing- 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ötige Abfragen.
- Frontend-Optimierung implementieren: Um den Stromverbrauch von Endnutzergeräten zu senken, verwenden Sie Strategien wie Minimierung, Komprimierung und Lazy Loading für Bilder und Assets.
Rechenaufwand minimieren
Um energieeffiziente Software zu schreiben, müssen Sie den Gesamtaufwand für die Berechnungen minimieren, die von Ihrer Anwendung ausgeführt werden. Jede unnötige Anweisung, jede redundante Schleife und jede zusätzliche Funktion verbraucht Energie, Zeit und Ressourcen. Verwenden Sie die folgenden Empfehlungen, um Software zu entwickeln, die nur minimale Berechnungen ausführt.
Schlanken, fokussierten Code schreiben
Verwenden Sie die folgenden Ansätze, um minimalen Code zu schreiben, der für die Erreichung der gewünschten Ergebnisse erforderlich ist:
- Redundante Logik und Feature-Bloat vermeiden: Schreiben Sie Code, der nur die wesentlichen Funktionen ausführt. Vermeiden Sie Funktionen, die den Rechenaufwand und die Komplexität erhöhen, aber keinen messbaren Mehrwert für Ihre Nutzer bieten.
- Refaktorieren: Prüfen Sie Ihre Anwendungen regelmäßig, um ungenutzte Funktionen zu ermitteln und die Energieeffizienz im Laufe der Zeit zu verbessern. Entfernen Sie solche Funktionen oder führen Sie ein Refactoring durch.
- 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 Lazy Evaluation, bei denen Berechnungen verzögert werden, bis 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 die Duplizierung und folgt dem DRY-Prinzip (Don't Repeat Yourself), das dazu beitragen kann, die CO2-Emissionen aus der Softwareentwicklung und ‑wartung zu reduzieren.
Backend-Caching verwenden
Durch das Backend-Caching wird sichergestellt, dass eine Anwendung nicht wiederholt dieselbe Arbeit ausführt. Eine hohe Cache-Trefferrate 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 Laufwerk-E/A-Vorgänge reduziert. Dadurch sinkt die Last auf die Datenbanken und Server im Backend.
- API-Antworten im Cache speichern: Um redundante und kostspielige Netzwerkaufrufe zu vermeiden, speichern Sie die Ergebnisse häufiger API-Anfragen im Cache.
- In-Memory-Caching priorisieren: Speichern Sie Daten im Hochgeschwindigkeitsspeicher (RAM), um langsame Laufwerk-E/A-Vorgänge und komplexe Datenbankabfragen zu vermeiden.
- Geeignete Strategien für das Schreiben in den Cache auswählen:
- 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 Anwendungen mit vielen Schreibvorgängen. Daten werden zuerst in den Cache geschrieben und die Datenbank wird später asynchron aktualisiert. Diese Strategie reduziert die unmittelbare Schreiblast auf langsamere Datenbanken.
- Intelligente Entfernungsrichtlinien verwenden: Halten Sie den Cache schlank und effizient. Verwenden Sie Richtlinien wie TTL (Time to Live), LRU (Least Recently Used) und LFU (Least Frequently Used), um veraltete oder wenig nützliche Daten zu entfernen und den verfügbaren Speicherplatz für häufig angeforderte Daten zu maximieren.
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 Speicheroperationen, die zum Ausführen einer Aufgabe erforderlich sind. Weniger CPU-Zyklen und Speicheroperationen führen zu einem geringeren Energieverbrauch.
Algorithmen für optimale Zeitkomplexität auswählen
Priorisieren Sie Algorithmen, die das gewünschte Ergebnis in der kürzestmöglichen Zeit erzielen. Dieser Ansatz trägt dazu bei, die Dauer der Ressourcennutzung zu verkürzen. Verwenden Sie die folgenden Ansätze, um Algorithmen auszuwählen, die die Ressourcennutzung optimieren:
- Komplexität reduzieren: Um die Komplexität zu bewerten, betrachten Sie nicht nur die Laufzeitmesswerte, sondern auch die theoretische Komplexität des Algorithmus. Im Vergleich zum Bubblesort reduziert der Mergesort beispielsweise die Rechenlast 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 im Framework. Diese Funktionen werden oft in einer niedrigeren und energieeffizienteren Sprache wie C oder C++ implementiert und sind daher besser für die zugrunde liegende Hardware optimiert als benutzerdefinierte Funktionen.
Datenstrukturen für Effizienz auswählen
Die von Ihnen ausgewählten Datenstrukturen bestimmen die Geschwindigkeit, mit der Daten abgerufen, eingefügt oder verarbeitet werden können. Diese Geschwindigkeit wirkt sich auf die CPU- und Arbeitsspeichernutzung aus. Verwenden Sie die folgenden Ansätze, um effiziente Datenstrukturen auszuwählen:
- Für Suche und Abruf optimieren: Bevorzugen Sie für häufige Vorgänge wie das Prüfen, ob ein Element vorhanden ist, oder das Abrufen eines bestimmten Werts Daten strukturen, die für Geschwindigkeit optimiert sind. Hashmaps oder Hashsets ermöglichen beispielsweise Suchvorgänge mit nahezu konstanter Zeit, was energieeffizienter ist als die lineare Suche in einem Array.
- Speicherbedarf minimieren: Effiziente Datenstrukturen tragen dazu bei, den gesamten Speicherbedarf einer Anwendung zu reduzieren. Ein geringerer Speicherzugriff und eine geringere Speicherverwaltung führen zu einem niedrigeren Stromverbrauch. Außerdem ermöglicht ein schlankeres Speicherprofil eine effizientere Ausführung von Prozessen, sodass Sie Ressourcenupgrades verschieben können.
- Spezielle 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 nur effizient auf den höchsten oder niedrigsten Wert zugreifen müssen.
Computing- und Datenvorgänge optimieren
Konzentrieren Sie sich bei der Softwareentwicklung auf eine effiziente und proportionale Ressourcennutzung im gesamten Technologie-Stack. Behandeln Sie CPU, Arbeitsspeicher, Laufwerk und Netzwerk als begrenzte und gemeinsam genutzte Ressourcen. Eine effiziente Nutzung von Ressourcen führt zu spürbaren Kostensenkungen und einem geringeren Energieverbrauch.
CPU-Auslastung und Leerlaufzeit optimieren
Verwenden Sie die folgenden Ansätze, um die Zeit zu minimieren, in der die CPU in einem aktiven, energieverbrauchenden Zustand ist, ohne sinnvolle Arbeit zu verrichten:
- Ereignisgesteuerte Logik gegenüber Polling bevorzugen: Ersetzen Sie ressourcenintensive Busy Loops oder ständiges 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 On-Demand-Verarbeitung, wodurch ressourcenintensive Abfragen überflüssig werden.
- Konstante hohe Frequenz vermeiden: Schreiben Sie Code, der die CPU nicht zwingt, ständig mit der höchsten Frequenz zu arbeiten. Um den Energieverbrauch zu minimieren, sollten Systeme im Leerlauf in Energiesparmodi oder Ruhemodi wechseln können.
- Asynchrone Verarbeitung verwenden: Verwenden Sie die asynchrone Verarbeitung, um zu verhindern, dass Threads während der Leerlaufzeiten gesperrt werden. Dieser Ansatz gibt Ressourcen frei und führt zu einer höheren Gesamtauslastung der Ressourcen.
Arbeitsspeicher 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 behalten. 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 mit nichtflüchtigen Speicherressourcen. Verwenden Sie beispielsweise einen Zwischenspeicher, um Daten zu speichern. Schreiben Sie die Daten in festen Intervallen oder wenn der Zwischenspeicher eine bestimmte Größe erreicht, in den nichtflüchtigen Speicher.
- Batchvorgänge: Fassen Sie häufige, kleine Laufwerksvorgänge zu 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 Laufwerke geschrieben oder von Laufwerken gelesen werden, indem Sie geeignete Datenkomprimierungstechniken anwenden. Um beispielsweise Daten zu komprimieren, die Sie in Cloud Storage speichern, können Sie dekompressive Transcodierungverwenden.
Netzwerkverkehr minimieren
Netzwerkressourcen verbrauchen bei Datenübertragungsvorgängen erhebliche Mengen an 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. Bevorzugen Sie beispielsweise HTTP/3 gegenüber HTTP/1.1, wählen Sie GraphQL gegenüber REST, verwenden Sie 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 Endnutzergeräte.
Frontend-Optimierung implementieren
Durch die Frontend-Optimierung wird die Menge der Daten minimiert, die Ihre Endnutzer herunterladen und verarbeiten müssen. Dadurch wird die Last auf die Ressourcen der Endnutzergeräte reduziert.
Code und Assets minimieren
Wenn Endnutzer kleinere und effizienter strukturierte Ressourcen herunterladen und verarbeiten müssen, verbrauchen ihre Geräte weniger Strom. Verwenden Sie die folgenden Techniken, um das Downloadvolumen und die Verarbeitungslast auf Endnutzergeräten zu minimieren:
- 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: Laden Sie Bilder, Videos und nicht kritische Assets erst, 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 der anfänglichen Datenübertragung und die Verarbeitungslast auf Endnutzergeräten.
- Kleinere JavaScript-Bundles: Entfernen Sie nicht verwendeten Code aus Ihren JavaScript Bundles mit modernen Modulbundlern und Techniken wie Tree Shaking. Dieser Ansatz führt zu kleineren 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. Das Browser-Caching trägt dazu bei, wiederholte Downloads und unnötigen Netzwerkverkehr bei nachfolgenden Besuchen zu vermeiden.
Leichte User Experience (UX) priorisieren
Das Design Ihrer Benutzeroberfläche kann erhebliche Auswirkungen auf die Rechenkomplexität beim Rendern von Frontend-Inhalten haben. Verwenden Sie die folgenden Techniken, um Frontend-Oberflächen zu erstellen, die eine leichte UX bieten:
- Effizientes Rendering: 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: Bevorzugen Sie nach Möglichkeit statische Websites oder progressive Web-Apps (PWAs). Solche Websites und Apps werden schneller geladen und erfordern weniger Serverressourcen.
- Barrierefreiheit und Leistung: Responsive, schnell ladende Websites 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 einer Studie von Deloitte und Google, Milliseconds Make Millions, führt eine um 0,1 Sekunden (100 ms) verbesserte Websitegeschwindigkeit zu einer Steigerung der Conversions um 8,4 % für Einzelhandelswebsites und zu einer Steigerung des durchschnittlichen Bestellwerts um 9,2 %.