Progettazione per la correzione automatica

Progettare l'applicazione in modo che sia in grado di eseguire la correzione automatica dei propri errori

In un sistema distribuito possono verificarsi errori. L'hardware può guastarsi. La rete, poi, può avere errori temporanei. Raramente un intero servizio, un data center o anche un'area di Azure subisce un'interruzione, ma anche quelli devono essere pianificati.

Progettare quindi un'applicazione che si auto-riparazione in caso di errori. Ciò richiede un approccio a tre fasi:

  • Rilevamento degli errori.
  • Risposta graduale agli errori.
  • Registrare e monitorare gli errori per fornire informazioni operative.

La modalità di risposta a un determinato tipo di errore può dipendere dai requisiti di disponibilità dell'applicazione. Ad esempio, se è necessaria la disponibilità elevata, è possibile distribuire in più zone di disponibilità in un'area. Per evitare interruzioni, anche nel caso improbabile di un'intera area di Azure che si verifica un'interruzione, è possibile eseguire automaticamente il failover in un'area secondaria durante un'interruzione a livello di area. Tuttavia, ciò comporta un costo più elevato e prestazioni potenzialmente inferiori rispetto a una distribuzione a singola area.

È bene inoltre non valutare solo eventi importanti come le interruzioni a livello di area, in genere rare. È consigliabile invece concentrarsi sulla gestione degli errori locali e di breve durata, ad esempio gli errori di connettività di rete o le connessioni di database non riuscite.

Consigli

Ritentare le operazioni non riuscite. Gli errori temporanei possono dipendere da una perdita momentanea della connettività di rete, da una connessione a un database eliminato o da un timeout che si verifica quando un servizio è occupato. Per gestire gli errori temporanei, nell'applicazione va prevista una logica di ripetizione dei tentativi. In molti servizi di Azure, l'SDK client implementa i tentativi automatici. Per altre informazioni, vedere Gestione degli errori temporanei e Modello di ripetizione dei tentativi.

Proteggere dagli errori i servizi remoti (Interruttore). Effettuare un tentativo dopo un errore temporaneo è un metodo valido, ma se il problema persiste può accadere che si ricevano segnalazioni di malfunzionamento del servizio da un numero eccessivo di chiamanti. Ciò può causare errori a catena durante il backup delle richieste. Usare il modello a interruttore per fallire e rispondere immediatamente agli errori, senza chiamata remota, quando un'operazione avrà probabilmente esito negativo.

Isolare le risorse critiche (A scomparti). Gli errori in un sottosistema possono propagarsi. Ciò può verificarsi se un errore causa alcune risorse, ad esempio thread o socket, non essere liberate in modo tempestivo, causando l'esaurimento delle risorse. Per evitare questo problema, usare il modello Bulkhead per partizionare un sistema in gruppi isolati in modo che un errore in una partizione non arresti l'intero sistema.

Adottare il livellamento del carico. Nelle applicazioni possono verificarsi picchi improvvisi di traffico sovraccaricano i servizi nel back-end. Per evitare questo problema, usare lo schema di livellamento del carico basato sulle code per inserire in coda gli elementi di lavoro per l'esecuzione asincrona. La coda si comporta come un buffer che contiene i picchi di carico.

Effettuare il failover. Se un'istanza non è raggiungibile, effettuare il failover su un'altra istanza. Per gli elementi senza stato, ad esempio un server Web, inserire più istanze dietro a un servizio di bilanciamento del carico o di gestione traffico. Per elementi che archiviano lo stato, ad esempio un database, usare le repliche e il failover. A seconda dell'archivio dati e della modalità di replica, l'applicazione potrebbe dover gestire la coerenza finale.

Compensare le transazioni non riuscite. In generale è consigliabile evitare le transazioni distribuite, in quanto richiedono il coordinamento tra servizi e risorse. In alternativa, creare un'operazione costituita da singole transazioni più piccole. Se l'operazione si interrompe prima del termine, usare il modello Transazioni di compensazione per annullare qualsiasi passaggio già completato.

Eseguire il checkpoint delle transazioni con esecuzione prolungata. I checkpoint possono fornire resilienza qualora un'operazione con esecuzione prolungata non riesca. Quando l'operazione si riavvia (ad esempio, viene prelevata da un'altra macchina virtuale), può essere ripresa a partire dall'ultimo checkpoint. Prendere in considerazione l'implementazione di un meccanismo che registra le informazioni sullo stato dell'attività a intervalli regolari e salvare questo stato in una risorsa di archiviazione durevole accessibile da qualsiasi istanza del processo che esegue l'attività. In questo modo, se il processo viene arrestato, il lavoro che stava eseguendo può essere ripreso a partire dall'ultimo checkpoint mediante un'altra istanza. Sono disponibili librerie che forniscono questa funzionalità, ad esempio NServiceBus e MassTransit. Vengono mantenuti in modo trasparente, in cui gli intervalli sono allineati all'elaborazione dei messaggi dalle code in bus di servizio di Azure.

Ridurre le prestazioni in modo graduale. In alcuni casi non è possibile risolvere un problema, ma è può risultare comunque utile offrire funzionalità ridotte. Si consideri un'applicazione in cui viene visualizzato un catalogo di libri. Nel caso in cui l'applicazione non possa recuperare l'immagine di anteprima di una copertina, si potrebbe visualizzare un'immagine segnaposto. Interi sottosistemi possono non essere critici per l'applicazione. Ad esempio, in un sito di e-commerce, la visualizzazione delle raccomandazioni sui prodotti è probabilmente meno critica rispetto all'elaborazione degli ordini.

Limitare i client. A volte un numero ridotto di utenti crea un carico eccessivo che può ridurre la disponibilità dell'applicazione per gli altri utenti. In questo caso, è utile limitare il client per un determinato periodo di tempo. Vedere Modello Limitazione.

Bloccare gli utenti malintenzionati. Applicare una limitazione a un client non implica necessariamente che questi abbia agito con cattive intenzioni. Significa semplicemente che ha superato la propria quota del servizio. Tuttavia, se un client supera spesso la propria quota o mostra un comportamento errato, è possibile bloccarlo. Definire un processo fuori banda affinché l'utente possa richiedere lo sblocco.

Usare il modello Designazione leader. Quando è necessario coordinare un'attività, usare il modello Designazione leader per selezionare un coordinatore. In questo modo, il coordinatore non rappresenta un singolo punto di guasto. In caso di errore, ne viene selezionato un altro. Se non si vuole implementare un algoritmo di designazione leader da zero, è possibile prendere in considerazione una soluzione preconfigurata, ad esempio Zookeeper.

Eseguire i test di inserimento degli errori. Accade spesso che venga testato il percorso di riuscita ma non il percorso di errore. Un sistema può essere eseguito nell'ambiente di produzione per lungo tempo prima che venga rilevato un percorso di errore. Usare i test di inserimento degli errori per testare la resilienza del sistema sia attivando errori reali sia simulandoli.

Adottare l'ingegneria del caos. La progettazione di Chaos estende la nozione di inserimento di errori inserendo in modo casuale errori o condizioni anomale nelle istanze di produzione.

Prendere in considerazione l'uso delle zone di disponibilità. Molte aree di Azure forniscono zone di disponibilità, ovvero set isolati di data center all'interno dell'area. Alcuni servizi di Azure possono essere distribuiti in modo zonally, assicurandosi che vengano posizionati in una zona specifica e possano ridurre la latenza nella comunicazione tra componenti nello stesso carico di lavoro. In alternativa, alcuni servizi possono essere distribuiti con ridondanza della zona, il che significa che Azure replica automaticamente la risorsa tra zone per la disponibilità elevata. Considerare quale approccio offre il miglior set di compromessi per la soluzione. Per altre informazioni su come progettare la soluzione per usare zone e aree di disponibilità, vedere Consigli per l'uso di zone e aree di disponibilità.

Per un approccio strutturato per la riparazione automatica delle applicazioni, vedere Progettare applicazioni affidabili per Azure.