Progetta per la scalabilità e la disponibilità elevata

Last reviewed 2023-08-05 UTC

Questo documento nel framework dell'architettura Google Cloud fornisce i principi di progettazione per progettare l'architettura dei tuoi servizi in modo che possano tollerare errori e fare lo scale in risposta alla domanda dei clienti. Un servizio affidabile continua a rispondere alle richieste dei clienti quando si verifica un'elevata domanda per il servizio o in caso di evento di manutenzione. I seguenti principi e best practice di progettazione dell'affidabilità dovrebbero far parte dell'architettura del sistema e del piano di deployment.

Crea ridondanza per una disponibilità superiore

I sistemi con esigenze di affidabilità elevate non devono avere single point of failure e le loro risorse devono essere replicate su più domini di errore. Un dominio in errore è un pool di risorse che possono causare errori in modo indipendente, ad esempio un'istanza VM, una zona o una regione. Quando esegui la replica tra i domini in errore, ottieni un livello aggregato di disponibilità più elevato rispetto a quello che potrebbe raggiungere le singole istanze. Per saperne di più, consulta Regioni e zone.

Come esempio specifico di ridondanza che potrebbe far parte dell'architettura del tuo sistema, per isolare gli errori nella registrazione DNS in singole zone, utilizza i nomi DNS di zona affinché le istanze sulla stessa rete possano accedere l'una all'altra.

Progetta un'architettura multizona con failover per una disponibilità elevata

Rendi la tua applicazione resiliente agli errori a livello di zona progettandola per utilizzare pool di risorse distribuiti in più zone con la replica dei dati, il bilanciamento del carico e il failover automatico tra zone. Esegui repliche a livello di zona di ogni livello dello stack di applicazioni ed elimina tutte le dipendenze tra zone nell'architettura.

Replica i dati tra regioni per il ripristino di emergenza

Replica o archivia i dati in una regione remota per abilitare il ripristino di emergenza in caso di interruzione regionale o perdita di dati. Quando viene utilizzata la replica, il ripristino è più rapido perché i sistemi di archiviazione nella regione remota contengono già dati quasi aggiornati, a parte la possibile perdita di una piccola quantità di dati a causa del ritardo di replica. Quando utilizzi l'archiviazione periodica anziché la replica continua, il ripristino di emergenza prevede il ripristino dei dati dai backup o dagli archivi in una nuova regione. Questa procedura di solito comporta tempi di inattività del servizio più lunghi rispetto all'attivazione di una replica del database aggiornata continuamente e potrebbe comportare una maggiore perdita di dati a causa del divario di tempo tra operazioni di backup consecutive. Qualunque sia l'approccio utilizzato, è necessario eseguire nuovamente il deployment dell'intero stack di applicazioni e avviarlo nella nuova regione, durante il quale il servizio non sarà disponibile.

Per una discussione dettagliata su concetti e tecniche di ripristino di emergenza, consulta Architettura del ripristino di emergenza in caso di interruzioni dell'infrastruttura cloud.

Progetta un'architettura multiregionale per la resilienza alle interruzioni regionali

Se il servizio deve essere eseguito ininterrottamente anche nel raro caso in cui un'intera regione non funzioni, progettalo in modo da utilizzare pool di risorse di calcolo distribuiti in diverse regioni. Esegui repliche a livello di regione di ogni livello dello stack delle applicazioni.

Utilizza la replica dei dati in più regioni e il failover automatico in caso di inattività di una regione. Alcuni servizi Google Cloud hanno varianti per più regioni, ad esempio Spanner. Per garantire la resilienza contro gli errori a livello di regione, utilizza questi servizi multiregionali nella tua progettazione, ove possibile. Per ulteriori informazioni sulle regioni e sulla disponibilità del servizio, consulta Località di Google Cloud.

Assicurati che non esistano dipendenze tra regioni in modo che l'impatto di un errore a livello di regione sia limitato a quella regione.

Elimina i single point of failure a livello di regione, ad esempio un database primario a livello di regione che potrebbe causare un'interruzione globale quando non è raggiungibile. Tieni presente che le architetture multiregionali spesso hanno un costo maggiore, quindi considera le esigenze aziendali rispetto al costo prima di adottare questo approccio.

Per ulteriori indicazioni sull'implementazione della ridondanza nei domini in errore, consulta il documento di sondaggio Deployment Archetypes for Cloud Applications (PDF).

Elimina i colli di bottiglia della scalabilità

Identifica i componenti del sistema che non possono crescere oltre i limiti delle risorse di una singola VM o di una singola zona. Alcune applicazioni scalano verticalmente, ovvero aggiungono più core della CPU, memoria o larghezza di banda di rete su una singola istanza VM per gestire l'aumento del carico. La scalabilità di queste applicazioni è limitata e spesso è necessario configurarle manualmente per far fronte alla crescita.

Se possibile, rinnova questi componenti per scalare orizzontalmente, ad esempio mediante il partizionamento o suddivisione in VM tra VM o zone. Per gestire l'aumento del traffico o dell'utilizzo, aggiungi altri shard. Utilizza tipi di VM standard che possono essere aggiunti automaticamente per gestire l'aumento del carico per shard. Per maggiori informazioni, consulta Pattern per app scalabili e resilienti.

Se non puoi riprogettare l'applicazione, puoi sostituire i componenti gestiti da te con servizi cloud completamente gestiti progettati per scalare orizzontalmente senza alcuna azione dell'utente.

Esegui la riduzione controllata dei livelli di servizio in caso di sovraccarico

Progetta i tuoi servizi in modo da tollerare il sovraccarico. I servizi dovrebbero rilevare il sovraccarico e restituire risposte di qualità inferiore all'utente o abbandonare parzialmente il traffico, non fallire completamente sotto sovraccarico.

Ad esempio, un servizio può rispondere alle richieste degli utenti con pagine web statiche e disattivare temporaneamente il comportamento dinamico più costoso da elaborare. Questo comportamento è descritto in dettaglio nel pattern di failover caldo da Compute Engine a Cloud Storage. In alternativa, il servizio può consentire operazioni di sola lettura e disattivare temporaneamente gli aggiornamenti dei dati.

Gli operatori devono essere avvisati di correggere la condizione di errore quando il servizio si riduce.

Previeni e riduci i picchi di traffico

Non sincronizzare le richieste tra i client. Troppi client che inviano traffico nello stesso istante causano picchi di traffico che potrebbero causare errori a cascata.

Implementa strategie di mitigazione dei picchi sul lato server come la limitazione, la queueing, l'eliminazione del carico o la interruzione dei circuiti, il degrado graduale e la priorità delle richieste critiche.

Le strategie di mitigazione sul client includono la limitazione lato client e il backoff esponenziale con tremolio.

Sanitizza e convalida gli input

Per evitare input errati, casuali o dannosi che causano interruzioni del servizio o violazioni della sicurezza, purifica e convalida i parametri di input per le API e gli strumenti operativi. Ad esempio, Apigee e Google Cloud Armor possono contribuire a proteggerti dagli attacchi di iniezione.

Usa regolarmente il fuzz test, in cui un test Bard chiama intenzionalmente le API con input casuali, vuoti o troppo grandi. Esegui questi test in un ambiente di test isolato.

Gli strumenti operativi devono convalidare automaticamente le modifiche alla configurazione prima dell'implementazione delle modifiche e devono rifiutare le modifiche se la convalida non va a buon fine.

Fail Safe in modo da preservare il funzionamento

Se si verifica un errore dovuto a un problema, i componenti di sistema non dovrebbero funzionare in modo da consentire all'intero sistema di continuare a funzionare. Questi problemi possono essere un bug del software, un input o una configurazione errati, un'interruzione non pianificata dell'istanza o un errore umano. Il processo dei servizi consente di determinare se dovresti essere eccessivamente permissivo o eccessivamente riduttivo, anziché eccessivamente restrittivo.

Considera i seguenti scenari di esempio e come rispondere in caso di errore:

  • In genere è preferibile che un componente firewall con una configurazione non valida o vuota non venga aperto e consenta al traffico di rete non autorizzato di passare per un breve periodo di tempo mentre l'operatore corregge l'errore. Questo comportamento mantiene il servizio disponibile, anziché essere chiuso senza errori e bloccare il 100% del traffico. Il servizio deve basarsi su controlli di autenticazione e autorizzazione più in profondità nello stack delle applicazioni per proteggere le aree sensibili mentre tutto il traffico passa attraverso.
  • Tuttavia, è preferibile che un componente server delle autorizzazioni che controlla l'accesso ai dati utente non venga chiuso correttamente e blocchi tutti gli accessi. Questo comportamento causa un'interruzione del servizio quando la configurazione è danneggiata, ma evita il rischio di fuga di dati utente riservati in caso di errore di apertura.

In entrambi i casi, l'errore dovrebbe generare un avviso ad alta priorità per consentire all'operatore di correggere la condizione di errore. I componenti del servizio non dovrebbero essere aperti correttamente, a meno che non comportino rischi estremi per l'azienda.

Progetta chiamate API e comandi operativi in modo che siano ripetibili

Le API e gli strumenti operativi devono rendere le chiamate sicure il più possibile per riprovare. Un approccio naturale a molte condizioni di errore è riprovare a eseguire l'azione precedente, ma potresti non sapere se il primo tentativo è riuscito.

L'architettura del sistema dovrebbe rendere le azioni idempotenti: se esegui l'azione identica su un oggetto due o più volte in successione, dovresti ottenere gli stessi risultati di una singola chiamata. Le azioni non idempotenti richiedono un codice più complesso per evitare il danneggiamento dello stato del sistema.

Identifica e gestisci le dipendenze del servizio

I designer e i proprietari dei servizi devono gestire un elenco completo delle dipendenze sugli altri componenti di sistema. La progettazione del servizio deve includere anche il ripristino da errori di dipendenza o una riduzione controllata se il ripristino completo non è fattibile. Tieni conto delle dipendenze dai servizi cloud utilizzati dal tuo sistema e da dipendenze esterne, ad esempio API di servizi di terze parti, riconoscendo che ogni dipendenza del sistema ha una percentuale di errori diversa da zero.

Quando imposti target di affidabilità, considera che lo SLO per un servizio è vincolato matematicamente dagli SLO di tutte le sue dipendenze critiche. Non puoi essere più affidabile dello SLO più basso di una delle dipendenze. Per ulteriori informazioni, consulta il calcolo della disponibilità dei servizi.

Dipendenze di avvio

All'avvio, i servizi si comportano in modo diverso rispetto a quelli in stato stazionario. Le dipendenze di avvio possono essere sensibilmente diverse da quelle in stato di runtime.

Ad esempio, all'avvio un servizio potrebbe dover caricare informazioni sull'utente o sull'account da un servizio di metadati utente che richiama raramente. Quando molte repliche di servizi si riavviano dopo un arresto anomalo o una manutenzione di routine, le repliche possono aumentare notevolmente il carico sulle dipendenze di avvio, soprattutto quando le cache sono vuote e devono essere ricompilate.

Testa l'avvio del servizio sotto carico ed esegui il provisioning delle dipendenze di avvio di conseguenza. Valuta una progettazione per eseguire la riduzione controllata salvando una copia dei dati recuperati da dipendenze di avvio critiche. Questo comportamento consente il riavvio del servizio con dati potenzialmente inattivi, anziché l'impossibilità di avviarsi quando una dipendenza critica ha un'interruzione. Il servizio può in seguito caricare dati aggiornati, ove possibile, per tornare al normale funzionamento.

Le dipendenze di avvio sono importanti anche quando esegui il bootstrap di un servizio in un nuovo ambiente. Progetta lo stack di applicazioni con un'architettura a più livelli, senza dipendenze cicliche tra i livelli. Le dipendenze cicliche possono sembrare tollerabili perché non bloccano le modifiche incrementali a una singola applicazione. Tuttavia, le dipendenze cicliche possono rendere difficile o impossibile il riavvio dopo che una emergenza ha rimosso l'intero stack di servizi.

Riduci al minimo le dipendenze critiche

Riduci al minimo il numero di dipendenze critiche per il tuo servizio, ovvero altri componenti i cui errori causeranno inevitabilmente interruzioni del servizio. Per rendere il tuo servizio più resiliente agli errori o alla lentezza degli altri componenti da cui dipende, considera le seguenti tecniche e principi di progettazione di esempio per convertire le dipendenze critiche in dipendenze non critiche:

  • Aumenta il livello di ridondanza nelle dipendenze critiche. L'aggiunta di più repliche riduce la probabilità che un intero componente non sia disponibile.
  • Utilizza le richieste asincrone ad altri servizi anziché bloccare una risposta o usa i messaggi di pubblicazione/sottoscrizione per disaccoppiare le richieste dalle risposte.
  • Memorizza nella cache le risposte di altri servizi per recuperare dall'indisponibilità a breve termine delle dipendenze.

Per rendere gli errori o la lentezza del servizio meno dannosi per altri componenti che dipendono da questo, prendi in considerazione le tecniche e i principi di progettazione riportati di seguito:

  • Utilizza code di richieste prioritarie e dai una priorità maggiore alle richieste in cui un utente sta aspettando una risposta.
  • Pubblica le risposte fuori dalla cache per ridurre latenza e carico.
  • Fail Safe in modo da preservare il funzionamento.
  • Esegui la riduzione controllata in caso di sovraccarico di traffico.

Assicurati che sia possibile eseguire il rollback di ogni modifica

Se non esiste un modo ben definito per annullare determinati tipi di modifiche a un servizio, modifica il design del servizio per supportare il rollback. Testa periodicamente il processo di rollback. È necessario eseguire il controllo della versione delle API per ogni componente o microservizio, garantendo la compatibilità con le versioni precedenti affinché le generazioni precedenti dei client continuino a funzionare correttamente con l'evoluzione dell'API. Questo principio di progettazione è essenziale per consentire un'implementazione progressiva delle modifiche all'API, con rollback rapido quando necessario.

Il rollback può essere costoso da implementare per le app mobile. Firebase Remote Config è un servizio di Google Cloud che semplifica il rollback delle funzionalità.

Non puoi eseguire rapidamente il rollback delle modifiche allo schema del database, quindi eseguile in più fasi. Progetta ogni fase per consentire la lettura e l'aggiornamento degli schemi sicuri da parte della versione più recente dell'applicazione e di quella precedente. Questo approccio di progettazione consente di eseguire in sicurezza il rollback in caso di problemi con la versione più recente.

Suggerimenti

Per applicare al tuo ambiente le indicazioni contenute nel framework dell'architettura, segui questi suggerimenti:

  • Implementa il backoff esponenziale con la randomizzazione nella logica dei nuovi tentativi di errore delle applicazioni client.
  • Implementa un'architettura multiregionale con failover automatico per l'alta disponibilità.
  • Utilizza il bilanciamento del carico per distribuire le richieste degli utenti tra shard e regioni.
  • Progetta l'applicazione in modo da eseguire correttamente la riduzione in caso di sovraccarico. Fornisci risposte parziali o fornisci funzionalità limitate anziché fallire del tutto.
  • Stabilire un processo basato sui dati per la pianificazione della capacità e utilizzare i test di carico e le previsioni di traffico per determinare quando eseguire il provisioning delle risorse.
  • Stabilire procedure di ripristino di emergenza e testarle periodicamente.

Passaggi successivi

Esplora altre categorie nel framework dell'architettura, come progettazione del sistema, eccellenza operativa e sicurezza, privacy e conformità.