REL 5: Come si progettano le interazioni in un sistema distribuito per mitigare o affrontare gli errori?
I sistemi distribuiti si basano sulle reti di comunicazione per interconnettere i componenti (ad esempio server o servizi). Il carico di lavoro deve funzionare in modo affidabile nonostante la perdita o la latenza dei dati su queste reti. I componenti del sistema distribuito devono funzionare in modo da non influire negativamente su altri componenti o sul carico di lavoro. Queste best practice consentono ai carichi di lavoro di affrontare stress o guasti, recuperare più rapidamente e mitigare l'impatto di tali problemi. Il risultato è un miglioramento del tempo medio di ripristino (MTTR).
Risorse
Retry, backoff, and jitter: AWS re:Invent 2019: Introducing The Amazon Builders’ Library
(DOP328)
Error Retries and Exponential Backoff in AWS
Amazon API Gateway: Throttle API Requests for Better Throughput
The Amazon Builders' Library: Timeouts, retries, and backoff with jitter
The Amazon Builders' Library: Avoiding fallback in distributed systems
The Amazon Builders' Library: Avoiding insurmountable queue backlogs
The Amazon Builders' Library: Caching challenges and strategies
Well-Architected lab: Level 300: Implementing Health Checks and Managing Dependencies
to Improve Reliability
CircuitBreaker (summarizes Circuit Breaker from “Release It!” book)
Michael Nygard “Release It! Design and Deploy Production-Ready Software”
Best practice:
-
Implementazione del degrado elegante per trasformare le dipendenze forti applicabili in dipendenze deboli: Quando le dipendenze di un componente non sono integre, il componente stesso può comunque funzionare, anche se in modo degradato. Ad esempio, quando una chiamata di dipendenza non riesce, utilizza invece una risposta statica predeterminata.
-
Richieste di throttling: Si tratta di un modello di mitigazione per rispondere a un aumento imprevisto della domanda. Alcune richieste vengono rispettate, ma quelle che superano un limite definito vengono rifiutate e restituiscono un messaggio che indica che sono state sottoposte a throttling. L'aspettativa per i client è che si ritirino e abbandonino la richiesta o riprovino a una velocità più lenta.
-
Controllo e limitazione delle chiamate di ripetizione: Utilizza il backoff esponenziale per eseguire nuovi tentativi dopo intervalli progressivamente più lunghi. Introduci il jitter per randomizzare gli intervalli di ripetizione e limitare il numero massimo di tentativi.
-
Errore rapido e limitazione delle code: Se il carico di lavoro non è in grado di rispondere correttamente a una richiesta, restituisce rapidamente un errore. Ciò consente il rilascio delle risorse associate a una richiesta e permette al servizio di recuperare se le risorse sono in esaurimento. Se il carico di lavoro è in grado di rispondere correttamente, ma la frequenza delle richieste è troppo elevata, utilizza una coda per eseguire il buffer delle richieste. Tuttavia, non consentire code lunghe che possono comportare l'elaborazione di richieste obsolete a cui il client ha già rinunciato.
-
Impostazione dei timeout dei client: Imposta i timeout in modo appropriato, verificali sistematicamente e non fare affidamento sui valori predefiniti poiché sono generalmente troppo alti
-
Rendere i servizi stateless laddove possibile: I servizi dovrebbero non richiedere lo stato oppure eseguire l'offload dello stato in modo tale che, tra diverse richieste client, non vi sia alcuna dipendenza dai dati archiviati localmente su disco o in memoria. In questo modo i server possono essere sostituiti a piacimento senza compromettere la disponibilità. Amazon ElastiCache o Amazon DynamoDB sono ottime destinazioni per lo stato di offload.
-
Implementazione di leve di emergenza: Si tratta di processi rapidi che possono mitigare l'impatto della disponibilità sul carico di lavoro. Possono essere utilizzati in assenza di una causa principale. Una leva di emergenza ideale riduce a zero il carico cognitivo dei resolver fornendo criteri di attivazione e disattivazione completamente deterministici. Le leve di esempio includono il blocco di tutto il traffico del robot o la distribuzione di una risposta statica. Le leve sono spesso manuali, ma possono anche essere automatizzate.
Piano di miglioramento
Implementazione del degrado elegante per trasformare le dipendenze forti applicabili
in dipendenze deboli
- Restituendo una risposta statica, il carico di lavoro mitiga gli errori che si verificano
nelle sue dipendenze
Well-Architected lab: Level 300: Implementing Health Checks and Managing Dependencies to Improve Reliability - Rileva quando è probabile che l'operazione di ripetizione non riesca e impedisci al
client di effettuare chiamate non riuscite con il modello dell'interruttore
CircuitBreaker
Richieste di throttling
- Utilizzo di Amazon API Gateway
Throttle API Requests for Better Throughput
Controllo e limitazione delle chiamate di ripetizione
Error Retries and Exponential Backoff in AWS
- Gli SDK di Amazon implementano questa funzionalità di default. Potrai implementare una logica similare nel tuo livello di dipendenze quando effettui chiamate ai tuoi servizi dipendenti. Potrai decidere quali sono i timeout e quando cessare i tentativi in base al tuo caso d'uso.
Errore rapido e limitazione delle code
- Implementazione d'errore rapido quando il servizio è eccessivamente sollecitato
Fail Fast - Limitazione delle code: In un sistema basato su code, quando l'elaborazione si interrompe ma i messaggi continuano
ad arrivare, il debito di messaggi può accumularsi in un backlog di grandi dimensioni,
determinando un aumento del tempo di elaborazione. Il lavoro potrebbe essere completato
troppo tardi perché i risultati siano utili, provocando essenzialmente il danneggiamento
della disponibilità che l'accodamento doveva evitare.
The Amazon Builders' Library: Avoiding insurmountable queue backlogs
Impostazione dei timeout dei client
AWS SDK: Retries and Timeouts
Rendere i servizi stateless laddove possibile
- Eliminazione dello stato che potrebbe effettivamente essere memorizzato nei parametri
di richiesta.
- Alcuni dati (come i cookie) possono passare nei titoli o nei parametri di query.
- Effettua il refactoring per rimuovere uno stato che può essere passato velocemente nelle richieste.
- Dopo aver esaminato se lo stato è necessario, sposta qualsiasi monitoraggio dello
stato in una cache multi-zona o un datastore resilienti come Amazon ElastiCache, Amazon
RDS, Amazon DynamoDB o una soluzione di dati distribuiti di terze parti: Memorizza uno stato impossibile da spostare in datastore resilienti.
- È possibile che alcuni dati non siano effettivamente necessari per richiesta e possano essere recuperati on demand.
- Rimuovi i dati recuperabili in modo asincrono.
- Scegli un datastore che soddisfi i requisiti per uno stato necessario.
- Valuta l'utilizzo di un database NoSQL per dati non relazionali.
Implementazione di leve di emergenza
- Suggerimenti per l'implementazione e l'utilizzo di leve di emergenza
- Quando le leve sono attivate, fai di meno, non di più
- Rendi le cose semplici, evita comportamenti bimodali
- Testare periodicamente le leve
- Di seguito sono elencati alcuni esempi di operazioni che NON rappresentano leve di
emergenza
- Aggiunta di capacità
- Chiamare i proprietari dei servizi dei client che dipendono dal tuo servizio e chiedere loro di ridurre le chiamate
- Apportare una modifica al codice e rilasciarlo