Questo principio del pilastro della sostenibilità del Google Cloud framework Well-Architected fornisce consigli per scrivere software che riduca al minimo il consumo energetico e il carico del server.
Panoramica del principio
Quando segui le best practice per creare le tue applicazioni cloud, ottimizzi l'energia utilizzata dalle risorse dell'infrastruttura cloud: AI, calcolo, storage e rete. Inoltre, contribuisci a ridurre il fabbisogno idrico dei data center e l'energia consumata dai dispositivi degli utenti finali quando accedono alle tue applicazioni.
Per creare software a basso consumo energetico, devi integrare considerazioni sulla sostenibilità durante l'intero ciclo di vita del software, dalla progettazione e dallo sviluppo al deployment, alla manutenzione e all'archiviazione. Per indicazioni dettagliate sull'utilizzo dell'AI per creare software che riduca al minimo l'impatto ambientale dei carichi di lavoro cloud, consulta l'ebook Google Cloud Crea software in modo sostenibile.
Consigli
I consigli in questa sezione sono raggruppati nelle seguenti aree di interesse:
- Riduci al minimo il lavoro computazionale: Prediligi un codice snello e mirato che elimini la logica ridondante ed eviti calcoli o funzionalità inutili.
- Utilizza algoritmi e strutture di dati efficienti: Scegli algoritmi efficienti in termini di tempo e memoria che riducano il carico della CPU e minimizzino l'utilizzo della memoria.
- Ottimizza le operazioni di calcolo e sui dati: sviluppa con l'obiettivo di utilizzare in modo efficiente tutte le risorse disponibili, tra cui CPU, memoria, I/O del disco e rete. Ad esempio, quando sostituisci i loop occupati con una logica basata sugli eventi, eviti il polling non necessario.
- Implementa l'ottimizzazione del frontend: per ridurre il consumo di energia dei dispositivi degli utenti finali, utilizza strategie come la minimizzazione, la compressione e il caricamento lento per immagini e asset.
Ridurre al minimo il lavoro computazionale
Per scrivere software a basso consumo energetico, devi ridurre al minimo la quantità totale di lavoro computazionale eseguito dalla tua applicazione. Ogni istruzione non necessaria, ciclo ridondante e funzionalità aggiuntiva consuma energia, tempo e risorse. Utilizza i seguenti suggerimenti per creare software che esegue calcoli minimi.
Scrivere codice snello e mirato
Per scrivere il codice minimo essenziale per ottenere i risultati richiesti, utilizza i seguenti approcci:
- Elimina la logica ridondante e l'eccesso di funzionalità: scrivi codice che esegue solo le funzioni essenziali. Evita funzionalità che aumentano il sovraccarico e la complessità di calcolo, ma non forniscono un valore misurabile per i tuoi utenti.
- Refactoring: per migliorare l'efficienza energetica nel tempo, esegui regolarmente un audit delle tue applicazioni per identificare le funzionalità inutilizzate. Intervieni per rimuovere o refactoring di queste funzionalità in modo appropriato.
- Evita operazioni non necessarie: non calcolare un valore o eseguire un'azione finché il risultato non è necessario. Utilizza tecniche come la valutazione pigra, che ritarda i calcoli finché un componente dipendente dell'applicazione non ha bisogno dell'output.
- Dai la priorità alla leggibilità e alla riutilizzabilità del codice: scrivi codice leggibile e riutilizzabile. Questo approccio riduce al minimo la duplicazione e segue il principio DRY (Don't Repeat Yourself), che può contribuire a ridurre le emissioni di anidride carbonica derivanti dallo sviluppo e dalla manutenzione del software.
Utilizzare la memorizzazione nella cache del backend
La memorizzazione nella cache del backend garantisce che un'applicazione non esegua lo stesso lavoro ripetutamente. Un elevato rapporto di hit della cache comporta una riduzione quasi lineare del consumo di energia per richiesta. Per implementare la memorizzazione nella cache del backend, utilizza le seguenti tecniche:
- Memorizza nella cache i dati frequenti: archivia i dati a cui si accede di frequente in una posizione di archiviazione temporanea e ad alte prestazioni. Ad esempio, utilizza un servizio di memorizzazione nella cache in memoria come Memorystore. Quando un'applicazione recupera dati da una cache, il volume di query del database e di operazioni I/O del disco viene ridotto. Di conseguenza, il carico sui database e sui server nel backend diminuisce.
- Memorizza nella cache le risposte API: per evitare chiamate di rete ridondanti e costose, memorizza nella cache i risultati delle richieste API frequenti.
- Dai la priorità alla memorizzazione nella cache in memoria: per eliminare le lente operazioni di I/O del disco e le query di database complesse, archivia i dati nella memoria ad alta velocità (RAM).
- Seleziona strategie di scrittura della cache appropriate:
- La strategia write-through garantisce che i dati vengano scritti in modo sincrono nella cache e nell'archivio permanente. Questa strategia aumenta la probabilità di hit della cache, quindi l'archivio permanente riceve meno richieste di lettura che richiedono molta energia.
- La strategia di write-back (write-behind) migliora le prestazioni delle applicazioni con molte scritture. I dati vengono scritti prima nella cache e il database viene aggiornato in modo asincrono in un secondo momento. Questa strategia riduce il carico di scrittura immediato sui database più lenti.
- Utilizza criteri di eliminazione intelligenti: mantieni la cache snella ed efficiente. Per rimuovere i dati obsoleti o di scarsa utilità e massimizzare lo spazio disponibile per i dati richiesti di frequente, utilizza criteri come durata (TTL), meno utilizzati di recente (LRU) e meno utilizzati di frequente (LFU).
Utilizzare algoritmi e strutture di dati efficienti
Gli algoritmi e le strutture di dati che scegli determinano la complessità computazionale grezza del tuo software. Quando selezioni algoritmi e strutture di dati appropriati, riduci al minimo il numero di cicli della CPU e le operazioni di memoria necessarie per completare un'attività. Un minor numero di cicli di CPU e operazioni di memoria comporta un consumo energetico inferiore.
Scegliere gli algoritmi per una complessità temporale ottimale
Dai la priorità agli algoritmi che raggiungono il risultato richiesto nel minor tempo possibile. Questo approccio contribuisce a ridurre la durata dell'utilizzo delle risorse. Per selezionare algoritmi che ottimizzano l'utilizzo delle risorse, utilizza i seguenti approcci:
- Concentrati sulla riduzione della complessità: per valutare la complessità, guarda oltre le metriche di runtime e considera la complessità teorica dell'algoritmo. Ad esempio, rispetto all'ordinamento a bolle, l'ordinamento per fusione riduce significativamente il carico computazionale e il consumo energetico per i set di dati di grandi dimensioni.
- Evita il lavoro ridondante: utilizza funzioni integrate e ottimizzate nel linguaggio di programmazione o nel framework che hai scelto. Queste funzioni vengono spesso implementate in un linguaggio di livello inferiore e più efficiente dal punto di vista energetico come C o C++, quindi sono ottimizzate meglio per l'hardware sottostante rispetto alle funzioni codificate personalizzate.
Selezionare le strutture di dati per l'efficienza
Le strutture di dati che scegli determinano la velocità con cui i dati possono essere recuperati, inseriti o elaborati. Questa velocità influisce sull'utilizzo di CPU e memoria. Per selezionare strutture di dati efficienti, utilizza i seguenti approcci:
- Ottimizza per la ricerca e il recupero: per operazioni comuni come controllare se un elemento esiste o recuperare un valore specifico, preferisci strutture di dati ottimizzate per la velocità. Ad esempio, le hash map o gli hash set consentono ricerche quasi costanti nel tempo, un approccio più efficiente dal punto di vista energetico rispetto alla ricerca lineare in un array.
- Ridurre al minimo l'impronta di memoria: strutture di dati efficienti contribuiscono a ridurre l'impronta di memoria complessiva di un'applicazione. La riduzione dell'accesso e della gestione della memoria comporta un minore consumo energetico. Inoltre, un profilo di memoria più snello consente ai processi di essere eseguiti in modo più efficiente, il che ti consente di posticipare gli upgrade delle risorse.
- Utilizza strutture specializzate: utilizza strutture di dati create appositamente per un determinato problema. Ad esempio, utilizza una struttura di dati trie per la ricerca rapida di prefissi di stringhe e una coda con priorità quando devi accedere in modo efficiente solo al valore più alto o più basso.
Ottimizzare le operazioni di calcolo e sui dati
Quando sviluppi software, concentrati sull'utilizzo efficiente e proporzionale delle risorse nell'intero stack tecnologico. Considera CPU, memoria, disco e rete come risorse limitate e condivise. Riconosci che l'utilizzo efficiente delle risorse porta a riduzioni tangibili dei costi e del consumo energetico.
Ottimizzare l'utilizzo della CPU e il tempo di inattività
Per ridurre al minimo il tempo che la CPU trascorre in uno stato attivo e di consumo energetico senza svolgere un lavoro significativo, utilizza i seguenti approcci:
- Preferisci la logica basata su eventi al polling: sostituisci i loop occupati o il controllo costante (polling) che richiedono molte risorse con la logica basata su eventi. Un'architettura basata su eventi garantisce che i componenti di un'applicazione funzionino solo quando vengono attivati da eventi pertinenti. Questo approccio consente l'elaborazione on demand, eliminando la necessità di polling a elevato consumo di risorse.
- Evita frequenze elevate costanti: scrivi codice che non costringa la CPU a funzionare costantemente alla frequenza più elevata. Per ridurre al minimo il consumo di energia, i sistemi inattivi devono essere in grado di entrare in stati di basso consumo o modalità di sospensione.
- Utilizza l'elaborazione asincrona: per evitare che i thread vengano bloccati durante i tempi di attesa inattivi, utilizza l'elaborazione asincrona. Questo approccio libera le risorse e porta a un maggiore utilizzo complessivo delle risorse.
Gestire in modo efficiente la memoria e l'I/O del disco
L'utilizzo inefficiente della memoria e del disco comporta un'elaborazione non necessaria e un aumento del consumo energetico. Per gestire in modo efficiente la memoria e l'I/O, utilizza le seguenti tecniche:
- Gestione rigorosa della memoria: intraprendi azioni per rilasciare in modo proattivo le risorse di memoria inutilizzate. Evita di conservare in memoria oggetti di grandi dimensioni per periodi di tempo più lunghi del necessario. Questo approccio previene i colli di bottiglia delle prestazioni e riduce la potenza consumata per l'accesso alla memoria.
- Ottimizza I/O del disco: riduci la frequenza delle interazioni di lettura e scrittura della tua applicazione con le risorse di archiviazione permanente. Ad esempio, utilizza un buffer di memoria intermedio per archiviare i dati. Scrivi i dati nello spazio di archiviazione persistente a intervalli fissi o quando il buffer raggiunge una determinata dimensione.
- Operazioni batch: consolida le operazioni su disco frequenti e di piccole dimensioni in un numero inferiore di operazioni batch più grandi. Un'operazione batch consuma meno energia rispetto a molte piccole transazioni individuali.
- Utilizza la compressione: riduci la quantità di dati scritti o letti dai dischi applicando tecniche di compressione dei dati adeguate. Ad esempio, per comprimere i dati archiviati in Cloud Storage, puoi utilizzare la transcodifica decompressiva.
Ridurre al minimo il traffico di rete
Le risorse di rete consumano una quantità significativa di energia durante le operazioni di trasferimento dei dati. Per ottimizzare la comunicazione di rete, utilizza le seguenti tecniche:
- Ridurre al minimo le dimensioni del payload: progetta le API e le applicazioni in modo da trasferire solo i dati necessari per una richiesta. Evita di recuperare o restituire strutture JSON o XML di grandi dimensioni nei casi in cui sono necessari solo pochi campi. Assicurati che le strutture di dati restituite siano concise.
- Ridurre i round trip: per ridurre il numero di round trip di rete necessari per completare un'azione dell'utente, utilizza protocolli più intelligenti. Ad esempio, preferisci HTTP/3 a HTTP/1.1, scegli GraphQL anziché REST, utilizza protocolli binari e consolida le chiamate API. Quando riduci il volume delle chiamate di rete, riduci il consumo energetico sia per i server che per i dispositivi degli utenti finali.
Implementare l'ottimizzazione del frontend
L'ottimizzazione del frontend riduce al minimo i dati che gli utenti finali devono scaricare ed elaborare, contribuendo a ridurre il carico sulle risorse dei dispositivi degli utenti finali.
Ridurre al minimo il codice e gli asset
Quando gli utenti finali devono scaricare ed elaborare risorse strutturate più piccole ed efficienti, i loro dispositivi consumano meno energia. Per ridurre al minimo il volume di download e il carico di elaborazione sui dispositivi degli utenti finali, utilizza le seguenti tecniche:
- Minimizzazione e compressione: per i file JavaScript, CSS e HTML, rimuovi i caratteri non necessari come spazi e commenti utilizzando strumenti di minimizzazione appropriati. Assicurati che i file come le immagini siano compressi e ottimizzati. Puoi automatizzare la minimizzazione e la compressione degli asset web utilizzando una pipeline CI/CD.
- Caricamento lento: carica immagini, video e asset non critici solo quando sono effettivamente necessari, ad esempio quando questi elementi scorrono nella viewport di una pagina web. Questo approccio riduce il volume di trasferimento dei dati iniziali e il carico di elaborazione sui dispositivi degli utenti finali.
- Bundle JavaScript più piccoli: elimina il codice inutilizzato dai bundle JavaScript utilizzando bundler di moduli moderni e tecniche come il tree shaking. Questo approccio produce file più piccoli che vengono caricati più velocemente e utilizzano meno risorse del server.
- Memorizzazione nella cache del browser: utilizza le intestazioni di memorizzazione nella cache HTTP per indicare al browser dell'utente di archiviare localmente gli asset statici. La memorizzazione nella cache del browser aiuta a evitare download ripetuti e traffico di rete non necessario nelle visite successive.
Dare la priorità a un'esperienza utente (UX) leggera
La progettazione dell'interfaccia utente può avere un impatto significativo sulla complessità computazionale per il rendering dei contenuti frontend. Per creare interfacce frontend che offrono un'esperienza utente leggera, utilizza le seguenti tecniche:
- Rendering efficiente: evita manipolazioni frequenti e a elevato consumo di risorse del Document Object Model (DOM). Scrivi codice che riduca al minimo la complessità del rendering ed elimini il rendering non necessario.
- Pattern di progettazione leggeri: se opportuno, preferisci siti statici o app web progressive (PWA). Questi siti e app si caricano più velocemente e richiedono meno risorse del server.
- Accessibilità e rendimento: i siti reattivi e a caricamento rapido sono spesso più sostenibili e accessibili. Un design ottimizzato e pulito riduce le risorse consumate durante il rendering dei contenuti. I siti web ottimizzati per prestazioni e velocità possono contribuire ad aumentare le entrate. Secondo uno studio di ricerca di Deloitte e Google, intitolato Milliseconds Make Millions, un miglioramento di 0,1 secondi (100 ms) nella velocità del sito comporta un aumento dell'8,4% delle conversioni per i siti di vendita al dettaglio e del 9,2% del valore medio dell'ordine.