Pattern per app scalabili e resilienti

Last reviewed 2024-03-19 UTC

Questo documento introduce alcuni pattern e pratiche per creare app resilienti e scalabili, due obiettivi essenziali di molti esercizi di architettura moderna. Un'app ben progettata si espande e si riduce in base all'aumento e alla diminuzione della domanda ed è sufficientemente resiliente per resistere alle interruzioni del servizio. La creazione e il funzionamento di app che soddisfano questi requisiti richiedono un'attenta pianificazione e progettazione.

Scalabilità: regolazione della capacità per soddisfare la domanda

La scalabilità è la misura della capacità di un sistema di gestire quantità variabili di lavoro aggiungendo o rimuovendo risorse dal sistema. Ad esempio, un'app web scalabile è un'app che funziona bene con un utente o con molti utenti e gestisce in modo elegante i picchi e i cali di traffico.

La flessibilità di adeguare le risorse consumate da un'app è un fattore chiave per le aziende che vogliono passare al cloud. Con una progettazione adeguata, puoi ridurre i costi rimuovendo le risorse sottoutilizzate senza compromettere le prestazioni o l'esperienza utente. Analogamente, puoi mantenere una buona esperienza utente durante i periodi di traffico elevato aggiungendo altre risorse. In questo modo, la tua app può consumare solo le risorse necessarie per soddisfare la domanda.

Google Cloud offre prodotti e funzionalità per aiutarti a creare app scalabili ed efficienti:

  • Le macchine virtuali Compute Engine e i cluster Google Kubernetes Engine (GKE) si integrano con gli autoscaler che ti consentono di aumentare o ridurre il consumo di risorse in base alle metriche che definisci.
  • La piattaforma serverless di Google Cloud fornisce servizi di calcolo, database e altri servizi gestiti che scalano rapidamente da zero a volumi di richieste elevati e paghi solo per ciò che utilizzi.
  • Prodotti di database come BigQuery, Spanner, e Bigtable possono offrire prestazioni coerenti su enormi dimensioni dei dati.
  • Cloud Monitoring fornisce metriche per le tue app e la tua infrastruttura, aiutandoti a prendere decisioni di scalabilità basate sui dati.

Resilienza: progettazione per far fronte agli errori

Un'app resiliente continua a funzionare nonostante i guasti dei componenti del sistema. La resilienza richiede una pianificazione a tutti i livelli dell'architettura. Influisce su come organizzi l'infrastruttura e la rete e su come progetti l'app e lo spazio di archiviazione dei dati. La resilienza si estende anche alle persone e alla cultura.

Creare e gestire app resilienti è difficile. Questo è particolarmente vero per le app distribuite, che potrebbero contenere più livelli di infrastrutture, reti e servizi. Gli errori e le interruzioni del servizio possono capitare e migliorare la resilienza della tua app è un percorso continuo. Con una pianificazione attenta, puoi migliorare la capacità della tua app di resistere agli errori. Con processi e cultura organizzativa adeguati, puoi anche imparare dagli errori per aumentare ulteriormente la resilienza della tua app.

Google Cloud fornisce strumenti e servizi per aiutarti a creare app resilienti e ad alta disponibilità:

  • I servizi Google Cloud sono disponibili in regioni e zone in tutto il mondo, il che ti consente di eseguire il deployment dell'app in modo da soddisfare al meglio i tuoi obiettivi di disponibilità.
  • I gruppi di istanze Compute Engine e i cluster GKE possono essere distribuiti e gestiti nelle zone disponibili di una regione.
  • I dischi permanenti a livello di regione di Compute Engine vengono replicati in modo sincrono tra le zone di una regione.
  • Google Cloud offre una serie di opzioni di bilanciamento del carico per gestire il traffico delle app, incluso il bilanciamento del carico globale che può indirizzare il traffico a una regione sana più vicina agli utenti.
  • La piattaforma serverless di Google Cloud include prodotti di calcolo e database gestiti che offrono ridondanza e bilanciamento del carico integrati.
  • Google Cloud supporta CI/CD tramite strumenti nativi e integrazioni con tecnologie open source di uso comune, per aiutarti ad automatizzare la creazione e il deployment delle tue app.
  • Cloud Monitoring fornisce metriche per le tue applicazioni e la tua infrastruttura, aiutandoti a prendere decisioni basate sui dati sulle prestazioni e sull'integrità delle tue applicazioni.

Driver e vincoli

Esistono diversi requisiti e motivazioni per migliorare la scalabilità e la resilienza della tua app. Potrebbero anche esserci vincoli che limitano la tua capacità di raggiungere i tuoi obiettivi di scalabilità e resilienza. L'importanza relativa di questi requisiti e vincoli varia a seconda del tipo di app, del profilo dei tuoi utenti e delle dimensioni e della maturità della tua organizzazione.

Driver

Per dare la priorità ai tuoi requisiti, prendi in considerazione i fattori determinanti delle diverse parti della tua organizzazione.

Fattori di crescita

I fattori comuni dal punto di vista aziendale includono:

  • Ottimizza i costi e il consumo delle risorse.
  • Riduci al minimo i tempi di inattività dell'app.
  • Assicurati che la domanda degli utenti possa essere soddisfatta durante i periodi di utilizzo elevato.
  • Migliorare la qualità e la disponibilità del servizio.
  • Assicurati che l'esperienza utente e la fiducia vengano mantenute durante eventuali interruzioni.
  • Aumenta la flessibilità e l'agilità per gestire le mutevoli esigenze del mercato.

Fattori di sviluppo

I fattori comuni dal punto di vista dello sviluppo includono:

  • Riduci al minimo il tempo impiegato per esaminare gli errori.
  • Aumentare il tempo dedicato allo sviluppo di nuove funzionalità.
  • Riduci al minimo il lavoro ripetitivo tramite l'automazione.
  • Crea app utilizzando le best practice e i pattern più recenti del settore.

Fattori chiave delle operazioni

I requisiti da considerare dal punto di vista operativo includono quanto segue:

  • Riduci la frequenza degli errori che richiedono l'intervento umano.
  • Aumenta la capacità di recuperare automaticamente dai guasti.
  • Riduci al minimo le attività ripetitive tramite l'automazione.
  • Riduci al minimo l'impatto del guasto di un determinato componente.

Vincoli

I vincoli potrebbero limitare la tua capacità di aumentare la scalabilità e la resilienza della tua app. Assicurati che le tue decisioni di progettazione non introducano o contribuiscano a questi vincoli:

  • Dipendenze da hardware o software difficili da scalare.
  • Dipendenze da hardware o software difficili da gestire in una configurazione di alta disponibilità.
  • Dipendenze tra le app.
  • Limitazioni relative alle licenze.
  • Mancanza di competenze o esperienza nei team di sviluppo e operazioni.
  • Resistenza dell'organizzazione all'automazione.

Modelli e best practice

La parte rimanente di questo documento definisce pattern e pratiche per aiutarti a creare app resilienti e scalabili. Questi pattern riguardano tutte le fasi del ciclo di vita dell'app, tra cui la progettazione dell'infrastruttura, l'architettura dell'app, le scelte di archiviazione, i processi di deployment e la cultura organizzativa.

Nei pattern sono evidenti tre temi:

  • Automazione. La creazione di app scalabili e resilienti richiede l'automazione. L'automazione del provisioning, dei test e dei deployment delle app dell'infrastruttura aumenta la coerenza e la velocità e riduce al minimo gli errori umani.
  • Accoppiamento lasco. Trattare il sistema come una raccolta di componenti indipendenti e debolmente accoppiati consente flessibilità e resilienza. L'indipendenza riguarda il modo in cui distribuisci fisicamente le risorse, come progetti la tua app e come progetti lo spazio di archiviazione.
  • Design basato sui dati. La raccolta delle metriche per comprendere il comportamento della tua app è fondamentale. Le decisioni su quando scalare l'app o su se un determinato servizio non è integro devono essere basate sui dati. Le metriche e i log devono essere funzionalità di base.

Automatizza il provisioning dell'infrastruttura

Crea un'infrastruttura immutabile tramite l'automazione per migliorare la coerenza dei tuoi ambienti e aumentare il successo dei tuoi implementazioni.

Tratta la tua infrastruttura come codice

Infrastructure as Code (IaC) è una tecnica che ti incoraggia a trattare il provisioning e la configurazione dell'infrastruttura nello stesso modo in cui gestisci il codice dell'applicazione. La logica di provisioning e configurazione viene archiviata nel controllo di origine in modo che sia rilevabile e possa essere sottoposta a controllo e a gestione delle versioni. Poiché si trova in un repository di codice, puoi sfruttare le pipeline di integrazione e deployment continui (CI/CD) in modo che eventuali modifiche alla configurazione possano essere testate e implementate automaticamente.

Rimuovendo i passaggi manuali dal provisioning dell'infrastruttura, IaC riduce al minimo gli errori umani e migliora la coerenza e la riproducibilità delle app e degli ambienti. In questo modo, l'adozione dell'IaC aumenta la resilienza delle tue app.

Cloud Deployment Manager consente di automatizzare la creazione e la gestione delle risorse Google Cloud con modelli flessibili. In alternativa, Config Connector ti consente di gestire le risorse utilizzando tecniche e flussi di lavoro di Kubernetes. Google Cloud offre anche il supporto integrato per i più diffusi strumenti IaC di terze parti, tra cui Terraform, Chef e Puppet.

Crea un'infrastruttura immutabile

L'infrastruttura immutabile è una filosofia che si basa sui vantaggi dell'infrastruttura come codice. L'infrastruttura immutabile prevede che le risorse non vengano mai modificate dopo il deployment. Se è necessario aggiornare una macchina virtuale, un cluster Kubernetes o una regola del firewall, puoi aggiornare la configurazione della risorsa nel repository di origine. Dopo aver testato e convalidato le modifiche, esegui nuovamente il deployment della risorsa utilizzando la nuova configurazione. In altre parole, anziché modificare le risorse, le ricrei.

La creazione di un'infrastruttura immutabile porta a deployment e rollback più prevedibili. Inoltre, riduce i problemi comuni nelle infrastrutture mutabili, come la deriva della configurazione e i server snowflake. In questo modo, l'adozione di un'infrastruttura immutabile migliora ulteriormente la coerenza e l'affidabilità dei tuoi ambienti.

Progetta per l'alta disponibilità

La disponibilità è una misura della frazione di tempo in cui un servizio è utilizzabile. La disponibilità viene spesso utilizzata come indicatore chiave dell'integrità complessiva del servizio. Le architetture ad alta disponibilità hanno lo scopo di massimizzare la disponibilità del servizio, in genere tramite il deployment ridondante dei componenti. In termini più semplici, per ottenere un'alta disponibilità in genere è necessario distribuire le risorse di calcolo, il bilanciamento del carico e la replica dei dati.

Distribuisci fisicamente le risorse

I servizi Google Cloud sono disponibili in località in tutto il mondo. Queste località sono suddivise in regioni e zone. Il modo in cui esegui il deployment dell'app in queste regioni e zone influisce sulla disponibilità, sulla latenza e su altre proprietà dell'app. Per saperne di più, consulta le best practice per la scelta della regione di Compute Engine.

La ridondanza è la duplicazione dei componenti di un sistema al fine di aumentare la disponibilità complessiva del sistema. In Google Cloud, la ridondanza viene solitamente ottenuta implementando l'app o il servizio in più zone o anche in più regioni. Se un servizio è disponibile in più zone o regioni, può resistere meglio alle interruzioni del servizio in una determinata zona o regione. Sebbene Google Cloud faccia di tutto per evitare interruzioni di questo tipo, alcuni eventi sono imprevedibili ed è meglio essere preparati.

Con i gruppi di istanze gestite di Compute Engine, puoi distribuire le istanze di macchine virtuali in più zone di una regione e gestirle come un'unità logica. Google Cloud offre inoltre dischi permanenti a livello di regione per replicare automaticamente i dati in due zone di una regione.

Analogamente, puoi migliorare la disponibilità e la resilienza delle app di cui è stato eseguito il deployment su GKE creando cluster regionali. Un cluster a livello di regione distribuisce i componenti, i nodi e i pod del piano di controllo GKE in più zone all'interno di una regione. Poiché i componenti del piano di controllo sono distribuiti, puoi continuare ad accedere al piano di controllo del cluster anche durante un'interruzione che coinvolge una o più zone (ma non tutte).

Favorire i servizi gestiti

Anziché installare, supportare e gestire in modo indipendente tutte le parti del tuo stack di applicazioni, puoi utilizzare i servizi gestiti per utilizzare parti del tuo stack di applicazioni come servizi. Ad esempio, anziché installare e gestire un database MySQL su macchine virtuali (VM), puoi utilizzare un database MySQL fornito da Cloud SQL. Riceverai un accordo sul livello del servizio (SLA) di disponibilità e potrai fare affidamento su Google Cloud per gestire la replica dei dati, i backup e l'infrastruttura di base. Utilizzando i servizi gestiti, puoi dedicare meno tempo alla gestione dell'infrastruttura e più tempo al miglioramento dell'affidabilità della tua app.

Molti dei servizi di calcolo, database e archiviazione gestiti di Google Cloud offrono ridondanza integrata, che può aiutarti a raggiungere i tuoi obiettivi di disponibilità. Molti di questi servizi offrono un modello regionale, il che significa che l'infrastruttura che esegue la tua app si trova in una regione specifica ed è gestita da Google in modo da essere disponibile in modo ridondante in tutte le zone all'interno di quella regione. Se una zona diventa non disponibile, l'app o i dati vengono pubblicati automaticamente da un'altra zona della regione.

Alcuni servizi di database e archiviazione offrono anche disponibilità multi-regionale, il che significa che l'infrastruttura che esegue la tua app si trova in diverse regioni. I servizi multi-regionali possono resistere alla perdita di un'intera regione, ma tipicamente a un costo di latenza più elevato.

Bilanciamento del carico a ogni livello

Il bilanciamento del carico ti consente di distribuire il traffico tra gruppi di risorse. Quando distribuisci il traffico, contribuisci ad assicurarti che le singole risorse non si sovraccarichino mentre altre rimangono inutilizzate. La maggior parte dei bilanciatori del carico fornisce anche funzionalità di controllo di integrità per garantire che il traffico non venga indirizzato a risorse non integre o non disponibili.

Google Cloud offre diverse opzioni di bilanciamento del carico. Se la tua app viene eseguita su Compute Engine o GKE, puoi scegliere il tipo di bilanciatore del carico più adatto in base al tipo, alla sorgente e ad altri aspetti del traffico. Per ulteriori informazioni, consulta la panoramica del bilanciamento del carico e la panoramica del networking di GKE.

In alternativa, alcuni servizi gestiti da Google Cloud, come App Engine e Cloud Run, bilanciano automaticamente il traffico.

È prassi comune bilanciare il carico delle richieste ricevute da origini esterne, come da client web o mobile. Tuttavia, l'utilizzo di bilanciatori del carico tra diversi servizi o livelli all'interno dell'app può anche aumentare la resilienza e la flessibilità. A questo scopo, Google Cloud fornisce il bilanciamento del carico interno per il livello 4 e il livello 7.

Il seguente diagramma mostra un bilanciatore del carico esterno che distribuisce il traffico mondiale in due regioni, us-central1 e asia-east1. Mostra inoltre il bilanciamento del carico interno che distribuisce il traffico dal livello web al livello interno all'interno di ogni regione.

Distribuzione del traffico globale tra le regioni.

Monitora la tua infrastruttura e le tue app

Prima di poter decidere come migliorare la resilienza e la scalabilità della tua app, devi comprenderne il comportamento. Avere accesso a un insieme completo di metriche e serie temporali pertinenti sul rendimento e sull'integrità della tua app può aiutarti a scoprire potenziali problemi prima che causino un'interruzione. Inoltre, possono aiutarti a diagnosticare e risolvere un'interruzione, se si verifica. Il capitolo sul monitoraggio dei sistemi distribuiti nel libro SRE di Google offre una buona panoramica di alcuni approcci al monitoraggio.

Oltre a fornire informazioni sull'integrità della tua app, le metriche possono essere utilizzate anche per controllare il comportamento della scalabilità automatica per i tuoi servizi.

Cloud Monitoring è lo strumento di monitoraggio integrato di Google Cloud. Cloud Monitoring importa eventi, metriche e metadati e fornisce approfondimenti tramite dashboard e avvisi. La maggior parte dei servizi Google Cloud invia automaticamente le metriche a Cloud Monitoring e Google Cloud supporta anche molte origini di terze parti. Cloud Monitoring può essere utilizzato anche come backend per i più diffusi strumenti di monitoraggio open source, fornendo un "pannello centralizzato" con cui osservare la tua app.

Monitoraggio a tutti i livelli

La raccolta delle metriche a vari livelli o livelli all'interno dell'architettura fornisce un quadro olistico dell'integrità e del comportamento della tua app.

Monitoraggio dell'infrastruttura

Il monitoraggio a livello di infrastruttura fornisce lo stato e le prestazioni di riferimento per la tua app. Questo approccio al monitoraggio acquisisce informazioni come il carico della CPU, l'utilizzo della memoria e il numero di byte scritti sul disco. Queste metriche possono indicare che una macchina è sovraccaricata o non funziona come previsto.

Oltre alle metriche raccolte automaticamente, Cloud Monitoring fornisce un agente che può essere installato per raccogliere informazioni più dettagliate dalle VM Compute Engine, incluse le app di terze parti in esecuzione su queste macchine.

Monitoraggio delle app

Ti consigliamo di acquisire le metriche a livello di app. Ad esempio, potresti voler misurare il tempo necessario per eseguire una determinata query o per eseguire una sequenza correlata di chiamate di servizio. Queste metriche a livello di app sono definite da te. Acquisiscono informazioni che non possono essere acquisite dalle metriche di Cloud Monitoring integrate. Le metriche a livello di app possono acquisire condizioni aggregate che riflettono più da vicino i flussi di lavoro principali e possono rivelare problemi che le metriche di infrastruttura di basso livello non rilevano.

Ti consigliamo inoltre di utilizzare OpenTelemetry per acquisire le metriche a livello di app. OpenTelemetry fornisce un unico standard aperto per i dati di telemetria. Utilizza OpenTelemetry per raccogliere ed esportare i dati dalle tue applicazioni e infrastrutture cloud-first. Puoi quindi monitorare e analizzare i dati di telemetria esportati.

Monitoraggio dei servizi

Per le app distribuite e basate su microservizi, è importante monitorare le interazioni tra i diversi servizi e componenti delle app. Queste metriche possono aiutarti a diagnosticare problemi come un aumento del numero di errori o la latenza tra i servizi.

Istio è uno strumento open source che fornisce approfondimenti e controllo operativo sulla tua rete di microservizi. Istio genera telemetria dettagliata per tutte le comunicazioni dei servizi e può essere configurato per inviare le metriche a Cloud Monitoring.

Monitoraggio end-to-end

Il monitoraggio end-to-end, chiamato anche monitoraggio black box, testa il comportamento visibile dall'esterno come lo vede un utente. Questo tipo di monitoraggio verifica se un utente è in grado di completare azioni critiche entro le soglie definite. Questo monitoraggio a granularità elevata può rilevare errori o latenze che un monitoraggio più granulare potrebbe non rilevare e rivela la disponibilità percepita dall'utente.

Mostrare l'integrità delle app

Un sistema ad alta disponibilità deve avere un modo per determinare quali parti del sistema sono in buone condizioni e funzionano correttamente. Se alcune risorse sembrano non essere in buono stato, il sistema può inviare le richieste altrove. In genere, i controlli di integrità prevedono il recupero dei dati da un endpoint per determinare lo stato o l'integrità di un servizio.

Il controllo di integrità è una responsabilità chiave dei bilanciatori del carico. Quando crei un bilanciatore del carico associato a un gruppo di istanze di macchine virtuali, definisci anche un controllo di integrità. Il controllo di integrità definisce in che modo il bilanciatore del carico comunica con le macchine virtuali per valutare se determinate istanze devono continuare a ricevere traffico. I controlli di integrità del bilanciatore del carico possono essere utilizzati anche per eseguire la riparazione automatica di gruppi di istanze in modo che le macchine non integre vengano ricreate. Se utilizzi GKE e esegui il bilanciamento del carico del traffico esterno tramite una risorsa Ingress, GKE crea automaticamente i controlli di salute appropriati per il bilanciatore del carico.

Kubernetes ha il supporto integrato per i probe di attività e di idoneità. Questi controlli aiutano l'orchestratore Kubernetes a decidere come gestire i pod e le richieste all'interno del cluster. Se l'app è dipiattaforma su Kubernetes, è buona norma esporre il suo stato a questi controlli tramite endpoint appropriati.

Definisci le metriche chiave

Il monitoraggio e i controlli di integrità forniscono metriche sul comportamento e sullo stato della tua app. Il passaggio successivo consiste nell'analizzare queste metriche per determinare quali sono le più descrittive o efficaci. Le metriche chiave variano a seconda della piattaforma su cui è implementata l'app e del lavoro che svolge.

È improbabile che tu trovi una sola metrica che indichi se scalare la tua app o se un determinato servizio non è in stato di esecuzione. Spesso si tratta di una combinazione di fattori che indicano insieme un determinato insieme di condizioni. Con Cloud Monitoring, puoi creare metriche personalizzate per rilevare queste condizioni. Il libro di Google sulla SRE consiglia quattro indicatori fondamentali per il monitoraggio di un sistema rivolto agli utenti: latenza, traffico, errori e saturazione.

Prendi in considerazione anche la tua tolleranza per i valori anomali. L'utilizzo di un valore medio o mediano per misurare l'integrità o il rendimento potrebbe non essere la scelta migliore, perché queste misure possono nascondere ampi squilibri. È quindi importante prendere in considerazione la distribuzione della metrica. Il 99° percentile potrebbe essere una misura più informativa rispetto alla media.

Definisci gli obiettivi del livello di servizio (SLO)

Puoi utilizzare le metriche raccolte dal sistema di monitoraggio per definire gli obiettivi del livello di servizio (SLO). Gli SLO specificano un livello target di prestazioni o affidabilità per il servizio. Gli SLO sono un pilastro fondamentale delle pratiche SRE e sono descritti in dettaglio nel capitolo sugli obiettivi del livello di servizio del libro SRE e anche nel capitolo sull'implementazione degli SLO del foglio di lavoro SRE.

Puoi utilizzare il monitoraggio del servizio per definire gli SLO in base alle metriche di Cloud Monitoring. Puoi creare criteri di avviso sugli SLO per sapere se corri il rischio di violare uno SLO.

Memorizza le metriche

Le metriche del sistema di monitoraggio sono utili a breve termine per eseguire controlli di integrità in tempo reale o per esaminare i problemi recenti. Cloud Monitoring conserva le metriche per diverse settimane per soddisfare al meglio questi casi d'uso.

Tuttavia, è utile anche archiviare le metriche di monitoraggio per analisi più a lungo termine. Avere accesso a un record storico può aiutarti ad adottare un approccio basato sui dati per perfezionare l'architettura dell'app. Puoi utilizzare i dati raccolti durante e dopo un'interruzione per identificare i colli di bottiglia e le interdipendenze nelle tue app. Puoi anche utilizzare i dati per creare e convalidare test significativi.

I dati storici possono anche aiutarti a verificare che la tua app supporti gli scopi commerciali durante i periodi chiave. Ad esempio, i dati possono aiutarti ad analizzare la scalabilità della tua app durante gli eventi promozionali con traffico elevato nel corso degli ultimi trimestri o addirittura anni.

Per informazioni dettagliate su come esportare e archiviare le metriche, consulta la soluzione Esportazione delle metriche di Cloud Monitoring.

Determina il profilo di scalabilità

Vuoi che la tua app soddisfi i suoi obiettivi di esperienza utente e rendimento senza eseguire un overprovisioning delle risorse.

Il seguente diagramma mostra una rappresentazione semplificata del profilo di scalabilità di un'app. L'app mantiene un livello di risorse di riferimento e utilizza la scalabilità automatica per rispondere alle variazioni della domanda.

Profilo di scalabilità dell'app.

Trova un equilibrio tra costo ed esperienza utente

Decidere se scalare l'app significa fondamentalmente bilanciare il costo rispetto all'esperienza utente. Decidi qual è il livello minimo di rendimento accettabile e, eventualmente, dove impostare un limite massimo. Queste soglie variare da app ad app e anche potenzialmente tra diversi componenti o servizi all'interno di un'unica app.

Ad esempio, un'app mobile o web rivolta ai consumatori potrebbe avere obiettivi di latenza rigorosi. La ricerca mostra che anche piccoli ritardi possono influire negativamente sulla percezione della tua app da parte degli utenti, conseguente riduzione delle conversioni e delle registrazioni. Pertanto, è importante assicurarti che la tua app abbia una capacità di pubblicazione sufficiente per rispondere rapidamente alle richieste degli utenti. In questo caso, i costi più elevati per l'esecuzione di più server web potrebbero essere giustificati.

Il rapporto costo/prestazioni potrebbe essere diverso per un'app interna non di importanza critica per l'attività, in cui gli utenti sono probabilmente più tolleranti di piccoli ritardi. Di conseguenza, il tuo profilo di scalabilità può essere meno aggressivo. In questo caso, mantenere bassi i costi potrebbe essere più importante dell'ottimizzazione dell'esperienza utente.

Imposta le risorse di riferimento

Un altro componente chiave del profilo di scalabilità è la scelta di un insieme minimo di risorse appropriato.

In genere, lo scale up delle macchine virtuali Compute Engine o dei cluster GKE richiede tempo, perché è necessario creare e inizializzare nuovi nodi. Pertanto, potrebbe essere necessario mantenere un insieme minimo di risorse, anche se non c'è traffico. Anche in questo caso, l'entità delle risorse di riferimento è influenzata dal tipo di app e dal profilo di traffico.

Al contrario, le tecnologie serverless come App Engine, le funzioni Cloud Run e Cloud Run sono progettate per scalare fino a zero e per avviarsi e scalare rapidamente, anche in caso di avvio a freddo. A seconda del tipo di app e del profilo di traffico, queste tecnologie possono offrire efficienza per parti della tua app.

Configura scalabilità automatica

La scalabilità automatica ti consente di scalare automaticamente le risorse di calcolo consumate dalla tua app. In genere, la scalabilità automatica si verifica quando vengono superate determinate metriche o quando vengono soddisfatte determinate condizioni. Ad esempio, se le latenze delle richieste al tuo livello web iniziano a superare un determinato valore, ti consigliamo di aggiungere automaticamente altre macchine per aumentare la capacità di pubblicazione.

Molti prodotti di calcolo di Google Cloud dispongono di funzionalità di scalabilità automatica. I servizi gestiti serverless come Cloud Run, le funzioni Cloud Run e App Engine sono progettati per scalare rapidamente. Questi servizi tipicamente offrono opzioni di configurazione per limitare o influenzare il comportamento della scalabilità automatica, ma in generale gran parte del comportamento del gestore della scalabilità automatica è nascosto all'operatore.

Compute Engine e GKE offrono più opzioni per controllare il comportamento di scalabilità. Con Compute Engine, puoi eseguire la scalabilità in base a vari input, tra cui le metriche personalizzate di Cloud Monitoring e la capacità di gestione del bilanciatore del carico. Puoi impostare limiti minimi e massimi per il comportamento di ridimensionamento e puoi definire un criterio di scalabilità automatica con più indicatori per gestire scenari diversi. Come per GKE, puoi configurare il gestore della scalabilità automatica dei cluster per aggiungere o rimuovere nodi in base alle metriche del carico di lavoro o dei pod oppure in base alle metriche esterne al cluster.

Ti consigliamo di configurare il comportamento di scalabilità automatica in base alle metriche chiave dell'app, al profilo di costo e al livello minimo di risorse richiesto definito.

Riduci al minimo il tempo di avvio

Affinché il ridimensionamento sia efficace, deve avvenire abbastanza rapidamente da gestire il carico in aumento. Questo è particolarmente vero quando aggiungi capacità di calcolo o di pubblicazione.

Utilizzare immagini pre-cotte

Se la tua app viene eseguita su VM Compute Engine, probabilmente devi installare il software e configurare le istanze per eseguirla. Sebbene tu possa utilizzare gli script di avvio per configurare nuove istanze, un modo più efficiente è creare un'immagine personalizzata. Un'immagine personalizzata è un disco di avvio configurato con il software e la configurazione specifici dell'app.

Per saperne di più sulla gestione delle immagini, consulta l'articolo sulle best practice per la gestione delle immagini.

Dopo aver creato l'immagine, puoi definire un modello di istanze. I modelli di istanza combinano l'immagine del disco di avvio, il tipo di macchina e altre proprietà dell'istanza. Puoi quindi utilizzare un modello di istanza per creare singole istanze VM o un gruppo di istanze gestite. I modelli di istanza sono un modo pratico per salvare la configurazione di un'istanza VM in modo da poterla utilizzare in seguito per creare nuove istanze VM identiche.

Sebbene la creazione di immagini e modelli di istanze personalizzati possa aumentare la velocità di implementazione, può anche aumentare i costi di manutenzione perché le immagini potrebbero dover essere aggiornate più di frequente. Per saperne di più, consulta la documentazione relativa al bilanciamento della configurazione delle immagini e della velocità di implementazione.

Containerizza l'app

Un'alternativa alla creazione di istanze VM personalizzate è la contenimento dell'app. Un container è un pacchetto software eseguibile, autonomo e leggero che include tutto il necessario per eseguire un'app: codice, runtime, strumenti di sistema, librerie di sistema e impostazioni. Queste caratteristiche rendono le app containerizzate più portatili, facili da implementare e da gestire su larga scala rispetto alle macchine virtuali. Inoltre, i container sono in genere rapidi da avviare, il che li rende adatti per app scalabili e resilienti.

Google Cloud offre diversi servizi per eseguire i container delle app. Cloud Run fornisce una piattaforma di calcolo serverless gestita per ospitare i tuoi container stateless. L'ambiente App Engine Flexible ospita i container in una piattaforma PaaS (Platform as a Service) gestita. GKE fornisce un ambiente Kubernetes gestito per ospitare e orchestrare le tue applicazioni containerizzate. Puoi anche eseguire i container dell'app su Compute Engine quando hai bisogno di un controllo completo sull'ambiente dei container.

Ottimizza l'app per un avvio rapido

Oltre ad assicurarti che l'infrastruttura e l'app possano essere implementate nel modo più efficiente possibile, è importante anche assicurarti che l'app venga messa online rapidamente.

Le ottimizzazioni appropriate per la tua app variano in base alle sue caratteristiche e alla piattaforma di esecuzione. È importante seguire questa procedura:

  • Individua ed elimina i colli di bottiglia creando il profilo delle sezioni critiche della tua app richiamate all'avvio.
  • Riduci il tempo di avvio iniziale implementando tecniche come l'inizializzazione dinamica, in particolare delle risorse costose.
  • Riduci al minimo le dipendenze dell'app che potrebbero dover essere caricate all'avvio.

Favorire architetture modulari

Puoi aumentare la flessibilità della tua app scegliendo architetture che consentono di eseguire il deployment, la gestione e la scalabilità dei componenti in modo indipendente. Questo pattern può anche migliorare la resilienza eliminando i single point of failure.

Suddividere l'app in servizi indipendenti

Se progetti la tua app come un insieme di servizi indipendenti e a basso accoppiamento, puoi aumentare la sua flessibilità. Se adotti un design a basso accoppiamento, puoi rilasciare ed eseguire il deployment dei servizi in modo indipendente. Oltre a molti altri vantaggi, questo approccio consente a questi servizi di utilizzare diversi stack tecnologici e di essere gestiti da team diversi. Questo approccio a a basso accoppiamento è il tema chiave di modelli di architettura come i microservizi e SOA.

Quando decidi come definire i confini dei tuoi servizi, i requisiti di disponibilità e scalabilità sono dimensioni chiave. Ad esempio, se un determinato componente ha un requisito di disponibilità o un profilo di scalabilità diverso rispetto agli altri componenti, potrebbe essere una buona scelta per un servizio autonomo.

Punta allo stato stateless

Un'app o un servizio stateless non conserva dati o stati locali permanenti. Un modello stateless ti consente di gestire ogni richiesta o interazione con il servizio indipendentemente dalle richieste precedenti. Questo modello facilita la scalabilità e il recupero, perché il servizio può crescere, diminuire o essere riavviato senza perdere i dati necessari per gestire eventuali richieste o processi in corso. L'assenza di stato è particolarmente importante quando utilizzi un'automazione di scalabilità, perché le istanze, i nodi o i pod che ospitano il servizio possono essere creati e distrutti in modo imprevisto.

Potrebbe non essere possibile che tutti i servizi siano senza stato. In questo caso, fornisci informazioni esplicite sui servizi che richiedono lo stato. Garantendo una separazione chiara tra i servizi stateless e stateful, puoi garantire una scalabilità semplice per i servizi stateless, adottando al contempo un approccio più ponderato per i servizi stateful.

Gestire la comunicazione tra i servizi

Una delle sfide delle architetture di microservizi distribuiti è la gestione della comunicazione tra i servizi. Man mano che la tua rete di servizi cresce, è probabile che aumenti anche le interdipendenze tra i servizi. Non vuoi che l'errore di un servizio provochi l'errore di altri servizi, a volte chiamato errore a cascata.

Puoi contribuire a ridurre il traffico verso un servizio sovraccaricato o in stato di errore adottando tecniche come il pattern di interruttore di sicurezza, i backoff esponenziali e la riduzione controllata. Questi pattern aumentano la resilienza dell'app dando ai servizi sovraccaricati la possibilità di recuperare o gestendo in modo elegante gli stati di errore. Per ulteriori informazioni, consulta il capitolo Gestire gli errori a cascata del libro Google SRE.

L'utilizzo di un mesh di servizi può aiutarti a gestire il traffico tra i tuoi servizi distribuiti. Un mesh di servizi è un software che collega i servizi e aiuta a disaccoppiare la logica di business dalla rete. Un mesh di servizi in genere fornisce funzionalità di resilienza come ripetizioni delle richieste, failover e interruttori di sicurezza.

Utilizza la tecnologia di archiviazione e del database appropriata

Alcuni database e tipi di archiviazione sono difficili da scalare e rendere resilienti. Assicurati che le tue scelte di database non limitino la disponibilità e la scalabilità della tua app.

Valuta le tue esigenze di database

Il modello di progettazione dell'app come insieme di servizi indipendenti si estende anche ai database e allo spazio di archiviazione. Potrebbe essere opportuno scegliere diversi tipi di archiviazione per parti diverse dell'app, il che si traduce in un'archiviazione eterogenea.

Le app convenzionali spesso funzionano esclusivamente con database relazionali. I database relazionali offrono funzionalità utili come transazioni, coerenza forte, integrità referenziale e query sofisticate tra le tabelle. Queste caratteristiche rendono i database relazionali una buona scelta per molte funzionalità comuni delle app. Tuttavia, i database relazionali presentano anche alcuni vincoli. Generalmente sono difficili da scalare e richiedono una gestione attenta in una configurazione ad alta disponibilità. Un database relazionale potrebbe non essere la scelta migliore per tutte le tue esigenze di database.

I database non relazionali, spesso indicati come database NoSQL, adottano un approccio diverso. Sebbene i dettagli variino da un prodotto all'altro, i database NoSQL tipicamente sacrificano alcune funzionalità dei database relazionali a favore di una maggiore disponibilità e una scalabilità più semplice. In termini di teorema CAP, i database NoSQL scelgono spesso la disponibilità rispetto alla coerenza.

Spesso la scelta di un database NoSQL dipende dal grado di coerenza richiesto. Se il modello dei dati per un determinato servizio non richiede tutte le funzionalità di un RDBMS e può essere progettato per essere eventualmente coerente, la scelta di un database NoSQL potrebbe offrire maggiore disponibilità e scalabilità.

Nel campo della gestione dei dati, i database relazionali e non relazionali sono spesso considerati tecnologie complementari anziché concorrenti. Utilizzando entrambi i tipi di database in modo strategico, le organizzazioni possono sfruttare i punti di forza di ciascuno per ottenere risultati ottimali in termini di archiviazione, recupero e analisi dei dati.

Oltre a una gamma di database relazionali e NoSQL, Google Cloud offre anche Spanner, un database molto coerente, altamente disponibile e distribuito a livello globale con supporto per SQL. Per informazioni su come scegliere un database appropriato su Google Cloud, consulta Database Google Cloud.

Implementa la memorizzazione nella cache

Lo scopo principale di una cache è aumentare le prestazioni di recupero dei dati riducendo la necessità di accedere al livello di archiviazione sottostante più lento.

La memorizzazione nella cache supporta una maggiore scalabilità riducendo la dipendenza dall'archiviazione basata su disco. Poiché le richieste possono essere inviate dalla memoria, le latenze delle richieste al livello di archiviazione vengono ridotte, in genere consentendo al servizio di gestire più richieste. Inoltre, la memorizzazione nella cache può ridurre il carico sui servizi downstream della tua app, in particolare sui database, consentendo anche ad altri componenti che interagiscono con il servizio downstream di scalare di più o di scalare.

La memorizzazione nella cache può anche aumentare la resilienza supportando tecniche come il degrado graduale. Se il livello di archiviazione sottostante è sovraccaricato o non disponibile, la cache può continuare a gestire le richieste. Anche se i dati restituiti dalla cache potrebbero essere incompleti o non aggiornati, questo potrebbe essere accettabile per determinati scenari.

Memorystore per Redis offre un servizio completamente gestito basato sull'archiviazione dei dati in memoria di Redis. Memorystore for Redis offre accesso a bassa latenza e un'elevata velocità effettiva per i dati a cui viene eseguito molto spesso l'accesso. Può essere implementato in una configurazione ad alta disponibilità che fornisce la replica tra zone e il failover automatico.

Modernizza i tuoi processi e la tua cultura di sviluppo

DevOps può essere considerata un'ampia raccolta di processi, cultura e strumenti che promuovono l'agilità e riducono il time to market di app e funzionalità rompendo i silos tra sviluppo, operazioni e team correlati. Le tecniche di DevOps hanno lo scopo di migliorare la qualità e l'affidabilità del software.

Una discussione dettagliata di DevOps non rientra nell'ambito di questo documento, ma alcuni aspetti chiave relativi al miglioramento dell'affidabilità e della resilienza della tua app sono trattati nelle sezioni seguenti. Per maggiori dettagli, consulta la pagina DevOps di Google Cloud.

Progettazione per la testabilità

I test automatici sono un componente chiave delle pratiche di distribuzione del software moderne. La possibilità di eseguire un insieme completo di test di unità, integrazione e sistema è essenziale per verificare che l'app si comporti come previsto e che possa procedere alla fase successiva del ciclo di implementazione. La testabilità è un criterio di progettazione fondamentale per la tua app.

Ti consigliamo di utilizzare i test di unità per la maggior parte dei test perché sono rapidi da eseguire e in genere semplici da gestire. Ti consigliamo inoltre di automatizzare i test di sistema e di integrazione di livello superiore. Questi test sono notevolmente semplificati se adotti tecniche di infrastruttura come codice, poiché è possibile creare ambienti e risorse di test dedicati on demand, per poi rimuoverli al termine dei test.

Con l'aumento della percentuale di codice coperta dai test, riduci l'incertezza e la potenziale diminuzione dell'affidabilità di ogni modifica al codice. Una copertura dei test adeguata ti consente di apportare più modifiche prima che l'affidabilità scenda al di sotto di un livello accettabile.

I test automatici sono un componente fondamentale dell'integrazione continua. L'esecuzione di un solido insieme di test automatici su ogni commit del codice fornisce un feedback rapido sulle modifiche, migliorando la qualità e l'affidabilità del software. Gli strumenti nativi di Google Cloud come Cloud Build e gli strumenti di terze parti come Jenkins possono aiutarti a implementare l'integrazione continua.

Automazione dei deployment

L'integrazione continua e l'automazione dei test completa ti garantiscono la stabilità del software. Una volta implementati, il passaggio successivo consiste nell'automatizzare il deployment dell'app. Il livello di automazione del deployment varia in base alla maturità della tua organizzazione.

La scelta di una strategia di deployment appropriata è essenziale per ridurre al minimo i rischi associati al deployment di nuovo software. Con la strategia giusta, puoi aumentare gradualmente l'esposizione delle nuove versioni a segmenti di pubblico più ampi, verificando il comportamento lungo il percorso. Puoi anche impostare delle disposizioni chiare per il rollback se si verificano problemi.

Adotta le pratiche di SRE per gestire gli errori

Per le app distribuite che operano su larga scala, è comune un certo grado di errore in uno o più componenti. Se adotti gli schemi descritti in questo documento, la tua app può gestire meglio le interruzioni causate da una release software difettosa, dall'interruzione imprevista di macchine virtuali o persino da un'interruzione dell'infrastruttura che interessa un'intera zona.

Tuttavia, anche con un design accurato dell'app, incontrerai inevitabilmente eventi imprevisti che richiedono l'intervento umano. Se implementi procedure strutturate per gestire questi eventi, puoi ridurne notevolmente l'impatto e risolverli più rapidamente. Inoltre, se esamini le cause e le risposte all'evento, puoi contribuire a proteggere la tua app da eventi simili in futuro.

Procedure efficaci per gestire gli incidenti ed eseguire analisi post mortem senza attribuzione delle colpe sono principi fondamentali dell'SRE. Anche se l'implementazione di tutte le pratiche di SRE di Google potrebbe non essere pratica per la tua organizzazione, se adotti anche un insieme minimo di linee guida, puoi migliorare la resilienza della tua app. Le appendici del libro SRE contengono alcuni modelli che possono aiutarti a definire le tue procedure.

Convalida e rivedi l'architettura

Man mano che l'app si evolve, il comportamento degli utenti, i profili di traffico e persino le priorità aziendali possono cambiare. Analogamente, anche altri servizi o l'infrastruttura di cui dipende la tua app possono evolversi. Pertanto, è importante testare e verificare periodicamente la resilienza e la scalabilità della tua app.

Testa la tua resilienza

È fondamentale verificare che l'app risponda agli errori nel modo previsto. Il tema principale è che il modo migliore per evitare gli errori è introdurli e imparare da essi.

Simulare e introdurre errori è complesso. Oltre a verificare il comportamento della tua app o del tuo servizio, devi anche assicurarti che vengano generati gli avvisi previsti e le metriche appropriate. Ti consigliamo un approccio strutturato, in cui vengono introdotti errori semplici e poi riassegnati.

Ad esempio, puoi procedere nel seguente modo, convalidando e documentando il comportamento in ogni fase:

  • Introduci errori intermittenti.
  • Bloccare l'accesso alle dipendenze del servizio.
  • Blocca tutte le comunicazioni di rete.
  • Terminare gli host.

Per maggiori dettagli, guarda il video Breaking your systems to make them unbreakable (Distruggere i sistemi per renderli indistruttibili) di Google Cloud Next 2019.

Se utilizzi un mesh di servizi come Istio per gestire i servizi per app, puoi iniettare errori a livello di applicazione anziché terminare i pod o le macchine oppure puoi iniettare pacchetti corrotti a livello di TCP. Puoi introdurre ritardi per simulare la latenza della rete o un sistema a monte sovraccaricato. Puoi anche introdurre interruzioni, che simulano i guasti nei sistemi a monte.

Testare il comportamento di scalabilità

Ti consigliamo di utilizzare i test non funzionali automatici per verificare che la tua app sia scalabile come previsto. Spesso questa verifica è associata a test di prestazioni o di carico. Puoi utilizzare strumenti semplici come hey per inviare il carico a un'app web. Per un esempio più dettagliato che mostra come eseguire il test di carico su un endpoint REST, consulta Test di carico distribuito con Google Kubernetes Engine.

Un approccio comune è assicurarsi che le metriche principali rimangano entro i livelli previsti per carichi variabili. Ad esempio, se stai testando la scalabilità del tuo livello web, potresti misurare le latenze medie delle richieste per volumi elevati di richieste degli utenti. Analogamente, per una funzionalità di elaborazione di backend, potresti misurare il tempo medio di elaborazione delle attività quando il volume delle attività aumenta improvvisamente.

Inoltre, vuoi che i test misurino che il numero di risorse create per gestire il carico di test rientra nell'intervallo previsto. Ad esempio, i test potrebbero verificare che il numero di VM create per gestire alcune attività di backend non superi un determinato valore.

È importante anche testare i casi limite. Qual è il comportamento della tua app o del tuo servizio quando vengono raggiunti i limiti massimi di scalabilità? Qual è il comportamento se il servizio viene ridotto e poi il carico aumenta di nuovo improvvisamente?

Progetta sempre

Il mondo della tecnologia si muove rapidamente e questo vale soprattutto per il cloud. Nuovi prodotti e funzionalità vengono rilasciati di frequente, emergono nuovi modelli e le richieste degli utenti e degli stakeholder interni continuano a crescere.

Come definito nel post del blog relativo ai principi dell'architettura cloud-native, cerca sempre modi per perfezionare, semplificare e migliorare l'architettura delle tue app. I sistemi software sono entità vive e devono adattarsi per riflettere le tue priorità in evoluzione.

Passaggi successivi

  • Leggi il post del blog sui principi per l'architettura cloud-native.
  • Leggi i libri SRE per informazioni dettagliate su come viene gestito l'ambiente di produzione di Google.
  • Scopri di più su come DevOps su Google Cloud può migliorare la qualità e l'affidabilità del tuo software.
  • Esplora architetture di riferimento, diagrammi e best practice su Google Cloud. Consulta il nostro Cloud Architecture Center.