Pattern per le app scalabili e resilienti

Last reviewed 2022-10-28 UTC

Questo documento introduce alcuni modelli e pratiche per la creazione di app resilienti e scalabili, due obiettivi essenziali di molti allenamenti moderni dell'architettura. Un'app ben progettata offre scale up e scale down man mano che la domanda aumenta e diminuisce ed è sufficientemente resiliente per resistere a interruzioni del servizio. La creazione e il funzionamento di app che soddisfano questi requisiti richiedono un'attenta pianificazione e progettazione.

Scalabilità: la regolazione della capacità per soddisfare la domanda

La scalabilità indica la capacità di un sistema di gestire quantità di lavoro variabili aggiungendo o rimuovendo risorse dal sistema. Ad esempio, un'app web scalabile è una che funziona bene con uno o più utenti e gestisce agevolmente i picchi e i cali di traffico.

La flessibilità per regolare le risorse utilizzate da un'app è un fattore chiave per il passaggio al cloud. Una progettazione adeguata può ridurre i costi rimuovendo le risorse sottoutilizzate senza compromettere le prestazioni o l'esperienza utente. Puoi mantenere un'esperienza utente positiva anche in periodi di traffico elevato aggiungendo più risorse. In questo modo, l'app può consumare solo le risorse necessarie per soddisfare la domanda.

Google Cloud fornisce 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 i gestori della scalabilità automatica che ti consentono di aumentare o ridurre il consumo di risorse in base a metriche da te definite.
  • La piattaforma serverless di Google Cloud fornisce computing gestito, database e altri servizi in grado di scalare rapidamente da zero a volumi di richieste elevati e ti consente di pagare solo per ciò che utilizzi.
  • Prodotti di database come BigQuery, Cloud Spanner e Cloud Bigtable possono offrire prestazioni coerenti su dimensioni di dati di grandi dimensioni.
  • Cloud Monitoring fornisce metriche nelle app e nell'infrastruttura, per aiutarti a prendere decisioni in merito alla scalabilità basate sui dati.

Resilienza: progettazione per resistere agli errori

Un'app resiliente continua a funzionare nonostante gli errori dei componenti di sistema. La resilienza richiede una pianificazione a tutti i livelli dell'architettura. Influenzano il modo in cui disponi l'infrastruttura e la rete e come progetti l'app e l'archiviazione di dati. La resilienza si estende anche alle persone e alla cultura.

Creare e utilizzare app resilienti è difficile. Ciò vale soprattutto per le app distribuite, che potrebbero contenere più livelli di infrastruttura, reti e servizi. Si verificano errori e interruzioni e migliorare la resilienza della tua app è un viaggio continuo. Con un'attenta pianificazione, puoi migliorare la capacità della tua app di resistere a errori. Con i processi adeguati e la cultura aziendale, puoi anche imparare dagli errori per aumentare ulteriormente la resilienza della tua app.

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

  • I servizi Google Cloud sono disponibili in aree geografiche e zone in tutto il mondo, consentendoti di eseguire il deployment della tua app per raggiungere i tuoi obiettivi di disponibilità.
  • I gruppi di istanze e i cluster GKE di Compute Engine possono essere distribuiti e gestiti tra le zone disponibili in una regione.
  • I dischi permanenti a livello di area geografica di Compute Engine vengono replicati in modo sincrono tra le zone in un'area geografica.
  • Google Cloud offre una gamma di opzioni di bilanciamento del carico per gestire il traffico delle app, tra cui il bilanciamento del carico globale che può indirizzare il traffico verso un'area geografica sana più vicina agli utenti.
  • La piattaforma serverless di Google Cloud include prodotti gestiti di database e computing che offrono ridondanza e bilanciamento del carico integrati.
  • Google Cloud supporta CI/CD tramite strumenti nativi e integrazioni con le più diffuse tecnologie open source per facilitare la creazione e il deployment delle tue app.
  • Cloud Monitoring fornisce metriche nelle tue app e nella tua infrastruttura per aiutarti a prendere decisioni basate sui dati in merito alle prestazioni e all'integrità delle tue app.

Driver e vincoli

Esistono diversi requisiti e motivazioni per migliorare la scalabilità e la resilienza della tua app. Potrebbero inoltre essere presenti vincoli che limitano la tua capacità di raggiungere gli obiettivi di scalabilità e resilienza. L'importanza relativa di questi requisiti e vincoli varia a seconda del tipo di app, del profilo degli utenti e della scalabilità e della maturità dell'organizzazione.

Driver

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

Driver aziendali

Ecco alcuni fattori comuni del lato commerciale:

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

Motori di sviluppo

Alcuni dei fattori più comuni da considerare sono i seguenti:

  • Riduci al minimo il tempo impiegato per analizzare gli errori.
  • Dedica più tempo allo sviluppo di nuove funzionalità.
  • Riduci al minimo il lavoro ripetitivo attraverso l'automazione.
  • Crea app utilizzando i modelli e le pratiche del settore più recenti.

Driver operativi

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

  • Riduci la frequenza degli errori che richiedono un intervento umano.
  • Aumenta la capacità di ripristino automatico dagli errori.
  • Riduci al minimo il lavoro ripetitivo attraverso l'automazione.
  • Riduci al minimo l'impatto del malfunzionamento di un particolare componente.

Limitazioni

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 hardware o software difficili da scalare.
  • Dipendenze da hardware o software difficili da utilizzare in una configurazione ad alta disponibilità.
  • Dipendenze tra app.
  • Limitazioni delle licenze.
  • Mancanza di competenze o esperienza nei team di sviluppo e operazioni.
  • Resistenza organizzativa all'automazione.

Modelli e pratiche

La parte restante di questo documento definisce pattern e pratiche per aiutarti a creare app resilienti e scalabili. Questi pattern riguardano tutte le parti 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 dell'organizzazione.

Questi pattern sono evidenti:

  • Automazione. La creazione di app scalabili e resilienti richiede l'automazione. L'automazione del provisioning, del test e del deployment delle app dell'infrastruttura aumenta la coerenza e la velocità e riduce al minimo gli errori umani.
  • Accoppiamento allentato. Trattare il sistema come una raccolta di componenti indipendenti e a basso accoppiamento consente flessibilità e resilienza. Indipendenza illustra il modo in cui distribuisci le risorse e come progetti l'app e progetti il tuo spazio di archiviazione.
  • Design basato sui dati. Raccogliere metriche per comprendere il comportamento della tua app è fondamentale. Le decisioni relative alla scalabilità dell'app o all'integrità di un determinato servizio devono essere basate sui dati. Le metriche e i log devono essere funzionalità principali.

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 deployment.

Considera la tua infrastruttura come un 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 del codice sorgente in modo che sia rilevabile e possa essere sottoposta al controllo delle versioni e sottoposta a controllo. Poiché si trova in un repository di codice, puoi sfruttare le pipeline di integrazione continua e deployment continuo (CI/CD), in modo che tutte le modifiche alla tua 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 di IaC aumenta la resilienza delle tue app.

Cloud Deployment Manager ti consente di automatizzare la creazione e la gestione delle risorse Google Cloud con modelli flessibili. In alternativa, Config Connector ti consente di gestire le tue risorse utilizzando tecniche e flussi di lavoro Kubernetes. Google Cloud offre anche 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. Un'infrastruttura immutabile impone che le risorse non vengano mai modificate dopo il deployment. Se è necessario aggiornare una macchina virtuale, un cluster Kubernetes o una regola firewall, puoi aggiornare la configurazione per la 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é ricrearle, puoi ricrearle.

La creazione di un'infrastruttura immutabile porta a deployment e rollback più prevedibili. Inoltre, mitiga i problemi comuni nelle infrastrutture mutabili, come le deviazioni dalla 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 un indicatore chiave di integrità del servizio. Le architetture ad alta disponibilità mirano a massimizzare la disponibilità del servizio, in genere attraverso il deployment di componenti in modo ridondante. In termini più semplici, il raggiungimento dell'alta disponibilità in genere prevede la distribuzione delle 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 divise 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à della tua app. Per ulteriori informazioni, consulta le best practice per la selezione della regione per Compute Engine.

Ridondanza è la duplicazione di componenti di un sistema per aumentarne la disponibilità complessiva. In Google Cloud, la ridondanza si ottiene in genere eseguendo il deployment dell'app o del servizio in più zone o persino in più aree geografiche. Se un servizio è presente in più zone o regioni, può resistere meglio alle interruzioni di servizio in una determinata zona o regione. Sebbene Google Cloud compia ogni sforzo per prevenire tali interruzioni, determinati eventi sono imprevedibili ed è meglio prepararsi.

Con i gruppi di istanze gestite di Compute Engine, puoi distribuire le istanze di macchine virtuali in più zone all'interno di un'area geografica e puoi gestire le istanze come un'unità logica. Google Cloud offre anche dischi permanenti a livello di area geografica per replicare automaticamente i dati in due zone di un'area geografica.

Allo stesso modo, puoi migliorare la disponibilità e la resilienza delle tue app di cui hai eseguito il deployment su GKE creando cluster a livello di area geografica. 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).

Preferisci servizi gestiti

Anziché installare, supportare e utilizzare in modo indipendente tutte le parti dello stack di applicazioni, puoi utilizzare i servizi gestiti per consumare parti dello 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. A quel punto ottieni un accordo sul livello del servizio (SLA) di disponibilità e puoi fare affidamento su Google Cloud per gestire la replica dei dati, i backup e l'infrastruttura sottostante. I servizi gestiti ti consentono di dedicare meno tempo alla gestione dell'infrastruttura e più tempo al miglioramento dell'affidabilità della tua app.

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

Alcuni servizi di database e archiviazione offrono anche una disponibilità multiregionale, il che significa che l'infrastruttura che esegue la tua app si trova in diverse aree geografiche. I servizi multiregionali possono tollerare la perdita di un'intera area geografica, ma in genere al costo di una latenza maggiore.

Bilanciamento del carico a ogni livello

Il bilanciamento del carico consente di distribuire il traffico tra gruppi di risorse. Quando distribuisci il traffico, contribuisci a evitare che le singole risorse si sovraccarichino quando altre rimangono inattive. La maggior parte dei bilanciatori del carico fornisce anche funzionalità di controllo di integrità per garantire che il traffico non sia instradato verso risorse in stato non integro o non disponibile.

Google Cloud offre diverse scelte per il bilanciamento del carico. Se la tua app viene eseguita su Compute Engine o GKE, puoi scegliere il tipo di bilanciatore del carico più appropriato in base al tipo, all'origine 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.

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

Il seguente diagramma mostra un bilanciatore del carico esterno che distribuisce il traffico globale tra due aree geografiche, us-central1 e asia-east1. Mostra inoltre il bilanciamento del carico interno che distribuisce il traffico dal livello web al livello interno di ogni area geografica.

Distribuzione del traffico globale tra regioni.

Monitora la tua infrastruttura e le tue app

Prima di decidere come migliorare la resilienza e la scalabilità della tua app, devi comprenderne il comportamento. Avere accesso a una serie completa di metriche e serie temporali pertinenti relative alle prestazioni e all'integrità della tua app può aiutarti a scoprire potenziali problemi prima che provochino interruzioni. Possono anche aiutarti a diagnosticare e risolvere un'interruzione, se si verifica. Il capitolo sul monitoraggio dei sistemi distribuiti nel libro di SRE di Google fornisce una buona panoramica di alcuni approcci al monitoraggio.

Oltre a fornire insight 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 insight 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" da cui osservare la tua app.

Monitora a tutti i livelli

La raccolta di metriche a vari livelli o livelli all'interno dell'architettura fornisce un quadro completo dello stato e del comportamento della tua app.

Monitoraggio dell'infrastruttura

Il monitoraggio a livello di infrastruttura offre prestazioni e integrità di base 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 su disco. Queste metriche possono indicare che una macchina è sovraccarica o non funziona come previsto.

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

Monitoraggio 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 il tempo necessario per eseguire una sequenza di chiamate di servizio correlate. Tu definisci queste metriche a livello di app. Acquisiscono informazioni che le metriche integrate di Cloud Monitoring non possono. Le metriche a livello di app possono acquisire condizioni aggregate che riflettono più fedelmente i flussi di lavoro chiave e possono rivelare problemi che le metriche dell'infrastruttura di basso livello non rilevano.

Consigliamo inoltre di utilizzare OpenCensus per acquisire le metriche a livello di app. OpenCensus è open source, fornisce un'API flessibile e può essere configurato per esportare le metriche nel backend Cloud Monitoring.

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 l'aumento del numero di errori o la latenza tra i servizi.

Istio è uno strumento open source che fornisce insight e controllo operativo sulla rete di microservizi. Istio genera dati di telemetria dettagliati per tutte le comunicazioni di servizio e può essere configurato in modo da inviare le metriche a Cloud Monitoring.

Monitoraggio end-to-end

Il monitoraggio end-to-end, chiamato anche monitoraggio black-box, verifica il comportamento visibile esternamente come viene visualizzato dall'utente. Questo tipo di monitoraggio controlla se un utente è in grado di completare azioni critiche entro le soglie definite. Questo monitoraggio granulare può rilevare errori o latenza che un monitoraggio più granulare potrebbe non avere e rivela la disponibilità percepita dall'utente.

Esponi lo stato delle tue app

Un sistema a disponibilità elevata deve avere un modo per determinare quali parti del sistema siano integre e funzionino correttamente. Se determinate risorse sembrano in stato non integro, il sistema può inviare richieste altrove. In genere, i controlli di integrità richiedono il estrazione 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 il modo in cui il bilanciatore del carico comunica con le macchine virtuali per valutare se una determinata istanza deve continuare a ricevere il traffico. I controlli di integrità del bilanciatore del carico possono essere utilizzati anche per riparare automaticamente i gruppi di istanze in modo da ricreare le macchine non integre. Se stai eseguendo su GKE e il bilanciamento del carico del traffico esterno attraverso una risorsa in entrata, GKE crea automaticamente controlli di integrità appropriati per il bilanciatore del carico.

Kubernetes include il supporto integrato per i probe di attività e di idoneità. Questi probe aiutano l'orchestratore Kubernetes a decidere come gestire pod e richieste all'interno del tuo cluster. Se viene eseguito il deployment dell'app su Kubernetes, è consigliabile esporre l'integrità dell'app a questi probe tramite gli endpoint appropriati.

Stabilisci le metriche chiave

Il monitoraggio e il controllo di integrità ti forniscono metriche sul comportamento e sullo stato della tua app. Il passaggio successivo consiste nell'analisi di queste metriche per determinare quali sono le più descrittive o di maggiore impatto. Le metriche principali variano a seconda della piattaforma su cui viene eseguito il deployment dell'app e del lavoro svolto.

Non è probabile che tu trovi una sola metrica che indica se scalare la tua app o se un determinato servizio non è integro. Spesso è una combinazione di fattori che indicano insieme un determinato insieme di condizioni. Con Cloud Monitoring, puoi creare metriche personalizzate per acquisire queste condizioni. Nel libro sulla SRE di Google sono riportati quattro segnali aurei per il monitoraggio di un sistema rivolto agli utenti: latenza, traffico, errori e saturazione.

Considera anche la tua tolleranza per i valori anomali. L'utilizzo di un valore medio o mediano per misurare lo stato o l'andamento potrebbe non essere la scelta migliore, poiché queste misure possono nascondere ampi squilibri. Pertanto, è importante considerare la distribuzione della metrica; il 99° percentile potrebbe essere una misura più informativa della media.

Definisci gli obiettivi del livello di servizio (SLO)

Puoi utilizzare le metriche raccolte dal tuo 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 chiave delle pratiche SRE e sono descritti in dettaglio nel capitolo dedicato agli obiettivi del livello di servizio del libro SRE e anche nel capitolo Implementazione degli SLO nel foglio di lavoro SRE.

Puoi utilizzare il monitoraggio dei servizi per definire gli SLO in base alle metriche in Cloud Monitoring. Puoi creare criteri di avviso per gli SLO per sapere se rischi di violare uno SLO.

Archivia le metriche

Le metriche del tuo sistema di monitoraggio sono utili nel breve periodo per agevolare i controlli di integrità in tempo reale o per indagare sui problemi recenti. Cloud Monitoring conserva le tue metriche per diverse settimane per soddisfare al meglio questi casi d'uso.

Tuttavia, l'archiviazione delle metriche di monitoraggio può essere utile anche per analisi 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 dipendenze nelle tue app. Puoi utilizzare questi dati anche per creare e convalidare test significativi.

I dati storici possono anche contribuire a verificare che la tua app supporti gli obiettivi commerciali durante i periodi chiave. Ad esempio, i dati possono aiutarti ad analizzare le dimensioni della tua app durante gli eventi promozionali ad alto traffico nel corso degli ultimi trimestri o persino di anni.

Per dettagli 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 raggiunga gli obiettivi relativi all'esperienza utente e alle prestazioni senza dover eseguire il provisioning eccessivo delle risorse.

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

Profilo di scalabilità dell'app.

Trova un equilibrio tra costo ed esperienza utente

Decidere se scalare l'app è fondamentalmente sul bilanciamento del costo rispetto all'esperienza utente. Stabilisci qual è il tuo livello minimo di rendimento accettabile e potenzialmente anche dove impostare un tetto. Queste soglie variano da un'app all'altra e potenzialmente anche in componenti o servizi diversi all'interno di una singola app.

Ad esempio, un'app web o per dispositivi mobili rivolta ai consumatori potrebbe avere obiettivi di latenza rigorosi. La ricerca mostra che anche piccoli ritardi possono influire negativamente sulla percezione che gli utenti hanno della tua app, riducendo così le conversioni e il numero di registrazioni. Pertanto, è importante assicurarsi che l'app abbia una capacità di pubblicazione sufficiente per rispondere rapidamente alle richieste degli utenti. In questo caso, i costi più elevati di esecuzione di più server web potrebbero essere giustificati.

Il rapporto costo/prestazioni potrebbe essere diverso per un'app interna non business-critical in cui gli utenti sono probabilmente più tolleranti di piccoli ritardi. Pertanto, il tuo profilo di scalabilità può essere meno aggressivo. In questo caso, mantenere i costi bassi potrebbe essere più importante che ottimizzare l'esperienza utente.

Imposta risorse di riferimento

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

In genere, per lo scale up delle macchine virtuali Compute Engine o dei cluster GKE è necessario del tempo, perché i nuovi nodi devono essere creati e inizializzati. Pertanto, potrebbe essere necessario mantenere un insieme minimo di risorse, anche in assenza di traffico. Anche in questo caso, l'entità delle risorse di riferimento è influenzata dal tipo di app e di profilo del traffico.

Al contrario, le tecnologie serverless come App Engine, Cloud Functions 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 di profilo del traffico, queste tecnologie possono fornire efficienza per parti della tua app.

Configura scalabilità automatica

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

Molti prodotti di computing di Google Cloud offrono funzionalità di scalabilità automatica. I servizi gestiti serverless come Cloud Run, Cloud Functions e App Engine sono progettati per la scalabilità rapida. Questi servizi in genere 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 della scalabilità. Con Compute Engine, puoi scalare 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 della scalabilità, oltre a definire un criterio di scalabilità automatica con più indicatori per gestire scenari diversi. Come con GKE, puoi configurare il gestore della scalabilità automatica del cluster per aggiungere o rimuovere i 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 della scalabilità automatica in base alle metriche principali dell'app, al profilo di costo e al livello minimo richiesto di risorse.

Riduci al minimo il tempo di avvio

Affinché la scalabilità sia efficace, deve avvenire abbastanza rapidamente da gestire il carico crescente. Ciò è particolarmente vero quando aggiungi capacità di calcolo o pubblicazione.

Utilizzare immagini preconfigurate

Se la tua applicazione viene eseguita su VM di Compute Engine, probabilmente devi installare software e configurare le istanze per eseguire l'applicazione. Sebbene sia possibile utilizzare script di avvio per configurare nuove istanze, un modo più efficiente è creare un'immagine personalizzata. Un'immagine personalizzata è un disco di avvio che hai impostato con il software e la configurazione specifici dell'app.

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

Quando hai creato l'immagine, puoi definire un modello di istanza. 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 istanze VM singole o un gruppo di istanze gestite. I modelli di istanza sono un modo conveniente 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 personalizzate e di modelli di istanza possa aumentare la velocità di deployment, può anche comportare un aumento dei costi di manutenzione, poiché le immagini devono essere aggiornate più spesso. Per ulteriori informazioni, consulta i documenti su bilanciamento delle immagini e configurazione della velocità di deployment.

Containerizzare l'app

Un'alternativa alla creazione di istanze VM personalizzate è la containerizzazione dell'app. Un container è un pacchetto software leggero, autonomo ed eseguibile 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ù portabili, semplificando il deployment e la manutenzione su larga scala rispetto alle macchine virtuali. Inoltre, in genere i container sono veloci e si avviano rapidamente, il che li rende adatti per app scalabili e resilienti.

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

Ottimizza la tua app per un avvio veloce

Oltre a garantire il deployment dell'infrastruttura e dell'app nel modo più efficiente possibile, è importante assicurarsi che la tua app sia online rapidamente.

Le ottimizzazioni appropriate per la tua app variano in base alle caratteristiche e alla piattaforma di esecuzione dell'app. È importante svolgere le seguenti operazioni:

  • Individua ed elimina i colli di bottiglia profilando le sezioni fondamentali della tua app richiamate all'avvio.
  • Riduci il tempo di avvio iniziale implementando tecniche come l'inizializzazione lazy, in particolare di risorse costose.
  • Riduci al minimo le dipendenze dell'app che potrebbero essere necessarie al momento dell'avvio.

Preferisci le architetture modulari

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

Suddividi la tua app in servizi indipendenti

Se progetti la tua app come un insieme di servizi indipendenti a basso accoppiamento, puoi aumentare la flessibilità della tua app. L'adozione di un design a basso accoppiamento consente ai tuoi servizi di essere rilasciati e sottoposti a deployment in modo indipendente. Oltre a molti altri vantaggi, questo approccio consente a questi servizi di utilizzare stack tecnici diversi e di essere gestiti da team diversi. Questo approccio a basso accoppiamento è il tema principale dei pattern dell'architettura come microservizi e SOA.

Quando valuti come definire i confini per i 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à diversi dagli altri componenti, potrebbe essere adatto a un servizio autonomo.

Per maggiori informazioni, consulta la pagina Migrazione di un'app monolitica in microservizi.

Mira a stateless

Un'app o un servizio stateless non conserva alcun dato o stato permanente locale. Un modello stateless assicura che tu possa gestire ogni richiesta o interazione con il servizio indipendentemente dalle richieste precedenti. Questo modello favorisce la scalabilità e la possibilità di recuperabilità perché significa che il servizio può crescere, ridursi o essere riavviato senza perdere i dati necessari per gestire le richieste o i processi in corso. L'utilità di stateless è particolarmente importante quando utilizzi un gestore della scalabilità automatica, perché le istanze, i nodi o i pod che ospitano il servizio possono essere creati ed eliminati in modo imprevisto.

Potrebbe non essere possibile che tutti i tuoi servizi siano stateless. In tal caso, spiega in modo esplicito i servizi che richiedono uno stato. Garantindo una separazione chiara dei servizi stateless e stateful, puoi garantire una facile scalabilità per i servizi stateless adottando un approccio più considerato per i servizi stateful.

Gestire la comunicazione tra i servizi

Una delle sfide con le architetture di microservizi distribuite è la gestione della comunicazione tra i servizi. Man mano che la tua rete di servizi cresce, è probabile che cresceranno anche le interdipendenze tra i servizi. Non vuoi che l'errore di un servizio determini l'errore di altri servizi, talvolta definito errore a cascata.

Puoi contribuire a ridurre il traffico verso un servizio sovraccaricato o un servizio in errore adottando tecniche come l'interruttore di sicurezza, il backoff esponenziale e il degrado grazioso. Questi pattern aumentano la resilienza della tua app dando ai servizi sovraccarichi la possibilità di recuperare o gestendo agevolmente gli stati di errore. Per ulteriori informazioni, consulta il capitolo affrontare gli errori a cascata nel libro SRE di Google.

L'utilizzo di un mesh di servizi può aiutarti a gestire il traffico tra i servizi distribuiti. Un mesh di servizi è un software che collega i servizi e aiuta a disaccoppiare la logica di business dal networking. Un mesh di servizi in genere offre funzionalità di resilienza come nuovi tentativi di richiesta, failover e interruttori di sicurezza.

Utilizza la tecnologia di archiviazione e database appropriata

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

Valuta le tue esigenze di database

Il pattern della progettazione della tua app come insieme di servizi indipendenti si estende anche ai tuoi database e allo spazio di archiviazione. Potrebbe essere opportuno scegliere diversi tipi di spazio di archiviazione per diverse parti della tua app, in modo da portare a uno spazio di archiviazione eterogeneo.

Le app tradizionali spesso funzionano esclusivamente con database relazionali. I database relazionali offrono funzionalità utili come transazioni, elevata coerenza, integrità referenziale e query sofisticate tra le tabelle. Queste funzionalità rendono i database relazionali un'ottima scelta per molte funzionalità di app comuni. Tuttavia, anche i database relazionali hanno alcuni vincoli. Sono in genere difficili da scalare e richiedono una gestione accurata 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 denominati database NoSQL, adottano un approccio diverso. Sebbene i dettagli varino tra i prodotti, in genere i database NoSQL sacrificano alcune funzionalità dei database relazionali a favore di una maggiore disponibilità e di una più semplice scalabilità. In termini di teorema CAP, i database Node spesso scelgono la disponibilità piuttosto che la coerenza.

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

Oltre a una serie di database relazionali e NoSQL, Google Cloud offre anche Cloud Spanner, un database a elevata coerenza, disponibilità elevata e distribuzione globale con supporto per SQL. Per informazioni sulla scelta di un database appropriato su Google Cloud, consulta i database Google Cloud.

Implementare la memorizzazione nella cache

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

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

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

Memorystore for Redis fornisce un servizio completamente gestito basato sul datastore in memoria Redis. Memorystore per Redis offre accesso a bassa latenza e velocità effettiva elevata per i dati a cui si accede in modo intensivo. Può essere eseguito in una configurazione ad alta disponibilità che fornisce replica tra zone e failover automatico.

Modernizza i tuoi processi di sviluppo e la tua cultura

DevOps può essere considerato un'ampia raccolta di processi, cultura e strumenti per promuovere l'agilità e una riduzione del time to market per app e funzionalità abbattendo le barriere tra sviluppo, operazioni e team correlati. Le tecniche DevOps mirano a migliorare la qualità e l'affidabilità del software.

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

Progettabilità per una verificabilità

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 la tua app si comporti come previsto e che possa passare alla fase successiva del ciclo di deployment. La verificabilità è un criterio di progettazione chiave per la tua app.

Ti consigliamo di utilizzare i test delle unità per la maggior parte del test, in quanto sono rapidi da eseguire e in genere facili da gestire. Ti consigliamo inoltre di automatizzare i test di integrazione e di sistema di livello superiore. Questi test sono molto semplificati se si adottano tecniche di Infrastructure as Code, perché le risorse e gli ambienti di test dedicati possono essere creati on demand e poi arrestati una volta completati.

Man mano che la percentuale di codebase coperta dai test aumenta, riduci l'incertezza e la potenziale diminuzione dell'affidabilità a ogni modifica del codice. Una copertura di test adeguata significa che puoi apportare ulteriori modifiche prima che l'affidabilità scenda al di sotto di un livello accettabile.

I test automatici sono un componente integrante dell'integrazione continua. Eseguire un solido insieme di test automatici su ciascun commit di codice fornisce un feedback rapido sulle modifiche, migliorando la qualità e l'affidabilità del tuo software. Strumenti Google Cloud-native come Cloud Build e strumenti di terze parti come Jenkins possono aiutarti a implementare l'integrazione continua.

Automazione dei deployment

L'integrazione continua e l'automazione di test completa ti garantiscono la stabilità del software. Una volta completata l'operazione, il passaggio successivo consiste nell'automazione del deployment dell'app. Il livello di automazione del deployment varia a seconda della maturità della tua organizzazione.

Scegliere 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 disposizioni chiare per il rollback in caso di problemi.

Adottare pratiche 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 i pattern trattati in questo documento, la tua app può gestire meglio le interruzioni causate da una release software difettosa, dall'arresto imprevisto di macchine virtuali o anche da un'interruzione dell'infrastruttura che interessa un'intera zona.

Tuttavia, anche con un'attenta progettazione delle app, si verificano inevitabilmente eventi imprevisti che richiedono un intervento umano. Se implementi i processi strutturati 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.

Le procedure efficaci per gestire gli incidenti ed eseguire post mortem senza attribuzione delle colpe sono aspetti fondamentali di SRE. Sebbene l'implementazione di tutte le pratiche di Google SRE possa non essere pratica per la tua organizzazione, se adotti anche solo una serie minima di linee guida puoi migliorare la resilienza della tua app. Le appendici del libro SRE contengono alcuni modelli che possono aiutarti a delineare i tuoi processi.

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, possono evolversi anche altri servizi o infrastrutture da cui la tua app dipende. Pertanto, è importante testare e convalidare periodicamente la resilienza e la scalabilità della tua app.

Verifica la tua resilienza

È fondamentale verificare che la tua app risponda agli errori nel modo previsto. Il tema generale è che il modo migliore per evitare è introdurre e propri errori.

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. Consigliamo un approccio strutturato, in cui introduci i semplici errori e poi esegui la riassegnazione.

Ad esempio, potresti procedere come segue, convalidare e documentare il comportamento in ogni fase:

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

Per i dettagli, guarda il video Breaking your system to make them inbreakable di Google Cloud Next 2019.

Se utilizzi un mesh di servizi come Istio per gestire i servizi delle app, puoi inserire gli errori a livello di applicazione invece di terminare i pod o le macchine oppure inserire i pacchetti a livello di TCP. Puoi introdurre ritardi per simulare la latenza di rete o un sistema upstream sovraccaricato. Puoi anche introdurre interruzioni, che imitano gli errori nei sistemi a monte.

Testa il comportamento di scalabilità

Consigliamo di utilizzare i test non funzionali automatici per verificare che l'app venga scalata come previsto. Spesso questa verifica è associata a test del rendimento o del 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 consiste nell'assicurarsi che le metriche chiave rimangano entro i livelli previsti per i 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 dei backend, è possibile misurare il tempo medio di elaborazione delle attività quando il volume delle attività aumenta improvvisamente.

Inoltre, vuoi che i tuoi test misurino che il numero di risorse create per gestire il carico di prova rientri 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.

È anche importante testare gli scenari perimetrali. Qual è il comportamento della tua app o del tuo servizio al raggiungimento dei limiti massimi di scalabilità? Qual è il comportamento se il servizio esegue lo scale down e quindi il carico aumenta improvvisamente di nuovo?

Architetta 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 la domanda degli utenti e degli stakeholder interni continua a crescere.

Come post definito dal principio dei principi per l'architettura cloud-native, cerca sempre modi per perfezionare, semplificare e migliorare l'architettura delle tue app. I sistemi software sono esseri viventi e devono adattarsi per riflettere le mutevoli priorità.

Passaggi successivi