Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.
Schema dell'interruttore
Intento
Lo schema di interruzione del circuito può impedire a un servizio chiamante di ritentare una chiamata a un altro servizio (chiamante) se in precedenza la chiamata ha causato ripetuti timeout o guasti. Lo schema viene utilizzato anche per rilevare quando il servizio chiamante è di nuovo operativo.
Motivazione
Quando più microservizi collaborano per gestire le richieste, uno o più servizi potrebbero non essere disponibili o presentare una latenza elevata. Quando applicazioni complesse utilizzano microservizi, un'interruzione di un microservizio può causare il fallimento dell'applicazione. I microservizi comunicano tramite chiamate di procedura remote e possono verificarsi errori transitori nella connettività di rete, con conseguenti guasti. (Gli errori transitori possono essere gestiti utilizzando il pattern retry with backoff). Durante l'esecuzione sincrona, la sovrapposizione di timeout o errori può causare un'esperienza utente scadente.
Tuttavia, in alcune situazioni, la risoluzione degli errori potrebbe richiedere più tempo, ad esempio quando il servizio chiamante non è attivo o se un conflitto nel database causa dei timeout. In questi casi, se il servizio chiamante riprova le chiamate ripetutamente, tali tentativi potrebbero causare conflitti di rete e il consumo del pool di thread del database. Inoltre, se più utenti riutilizzano l'applicazione ripetutamente, ciò aggraverà il problema e potrebbe causare un peggioramento delle prestazioni dell'intera applicazione.
Lo schema degli interruttori automatici è stato reso popolare da Michael Nygard nel suo libro Release It (Nygard 2018). Questo modello di progettazione può impedire a un servizio chiamante di ritentare una chiamata di servizio che in precedenza aveva causato ripetuti timeout o guasti. È inoltre in grado di rilevare quando il servizio chiamante è di nuovo operativo.
Gli oggetti dell'interruttore funzionano come interruttori elettrici che interrompono automaticamente la corrente quando si verifica un'anomalia nel circuito. Gli interruttori elettrici interrompono o fanno scattare il flusso di corrente in caso di guasto. Allo stesso modo, l'oggetto interruttore si trova tra il chiamante e il servizio chiamante e interviene se il chiamante non è disponibile.
Gli errori del calcolo distribuito sono un insieme di
Durante un'interruzione della rete, le applicazioni potrebbero attendere una risposta a tempo indeterminato e consumare continuamente le risorse dell'applicazione. La mancata ripetizione delle operazioni quando la rete diventa disponibile può anche portare al degrado delle applicazioni. Se API le chiamate a un database o a un servizio esterno si interrompono a causa di problemi di rete, le chiamate ripetute senza interruttore automatico possono influire sui costi e sulle prestazioni.
Applicabilità
Usa questo schema quando:
-
Il servizio chiamante effettua una chiamata che molto probabilmente non andrà a buon fine.
-
Un'elevata latenza mostrata dal servizio chiamante (ad esempio, quando le connessioni al database sono lente) causa dei timeout per il servizio chiamante.
-
Il servizio chiamante effettua una chiamata sincrona, ma il servizio chiamante non è disponibile o presenta una latenza elevata.
Problemi e considerazioni
-
Implementazione indipendente dal servizio: per evitare il gonfiamento del codice, si consiglia di implementare l'oggetto circuit breaker in modo indipendente dai microservizi e basato sui microservizi. API
-
Chiusura del circuito da parte del chiamante: quando il chiamante si riprende dal problema o dal guasto delle prestazioni, può aggiornare lo stato del circuito a.
CLOSED
Si tratta di un'estensione dello schema degli interruttori automatici e può essere implementata se l'obiettivo del tempo di ripristino () RTO lo richiede. -
Chiamate multithread: il valore del timeout di scadenza è definito come il periodo di tempo in cui il circuito rimane attivo prima che le chiamate vengano nuovamente instradate per verificare la disponibilità del servizio. Quando il servizio chiamante viene chiamato in più thread, la prima chiamata non riuscita definisce il valore del timeout di scadenza. L'implementazione deve garantire che le chiamate successive non spostino il timeout di scadenza all'infinito.
-
Apertura o chiusura forzata del circuito: gli amministratori di sistema devono avere la possibilità di aprire o chiudere un circuito. Ciò può essere fatto aggiornando il valore del timeout di scadenza nella tabella del database.
-
Osservabilità: l'applicazione deve avere una registrazione configurata per identificare le chiamate che falliscono quando l'interruttore è aperto.
Implementazione
Architettura di alto livello
Nell'esempio seguente, il chiamante è il servizio ordini e il chiamante è il servizio di pagamento.
In assenza di guasti, il servizio ordini indirizza tutte le chiamate al servizio di pagamento tramite l'interruttore automatico, come illustrato nello schema seguente.
In caso di timeout del servizio di pagamento, l'interruttore automatico è in grado di rilevare il timeout e tracciare l'errore.
Se i timeout superano una soglia specificata, l'applicazione apre il circuito. Quando il circuito è aperto, l'oggetto interruttore automatico non indirizza le chiamate al servizio di pagamento. Quando il servizio di ordinazione chiama il servizio di pagamento, restituisce un errore immediato.
L'oggetto circuit breaker cerca periodicamente di verificare se le chiamate al servizio di pagamento hanno esito positivo.
Quando la chiamata al servizio di pagamento ha esito positivo, il circuito viene chiuso e tutte le altre chiamate vengono nuovamente indirizzate al servizio di pagamento.
Implementazione tramite servizi AWS
La soluzione di esempio utilizza flussi di lavoro rapidi AWS Step Functions
La soluzione utilizza anche una tabella Amazon DynamoDB
Quando un servizio desidera chiamare un altro servizio, avvia il flusso di lavoro con il nome del servizio chiamante. Il flusso di lavoro ottiene lo stato dell'interruttore automatico dalla tabella CircuitStatus
DynamoDB, che memorizza i servizi attualmente danneggiati. Se CircuitStatus
contiene un record non scaduto per il chiamante, il circuito è aperto. Il flusso di lavoro Step Functions restituisce un errore immediato e termina con uno FAIL
stato.
Se la CircuitStatus
tabella non contiene un record per il chiamante o contiene un record scaduto, il servizio è operativo. Il ExecuteLambda
passaggio nella definizione della macchina a stati richiama la funzione Lambda che viene inviata tramite un valore di parametro. Se la chiamata ha esito positivo, il flusso di lavoro Step Functions termina con uno SUCCESS
stato.
Se la chiamata di servizio fallisce o si verifica un timeout, l'applicazione riprova con un backoff esponenziale per un numero definito di volte. Se la chiamata di servizio fallisce dopo i nuovi tentativi, il flusso di lavoro inserisce un record nella CircuitStatus
tabella del servizio con l'an ExpiryTimeStamp
e il flusso di lavoro termina con uno stato. FAIL
Le chiamate successive allo stesso servizio restituiscono un errore immediato finché l'interruttore è aperto. La Get Circuit Status
fase di definizione della macchina a stati verifica la disponibilità del servizio in base al ExpiryTimeStamp
valore. Gli elementi scaduti vengono eliminati dalla CircuitStatus
tabella utilizzando la funzionalità time to live () di DynamoDB. TTL
Codice di esempio
Il codice seguente utilizza la funzione GetCircuitStatus
Lambda per controllare lo stato dell'interruttore.
var serviceDetails = _dbContext.QueryAsync<CircuitBreaker>(serviceName, QueryOperator.GreaterThan, new List<object> {currentTimeStamp}).GetRemainingAsync(); if (serviceDetails.Result.Count > 0) { functionData.CircuitStatus = serviceDetails.Result[0].CircuitStatus; } else { functionData.CircuitStatus = ""; }
Il codice seguente mostra le istruzioni di Amazon States Language nel flusso di lavoro Step Functions.
"Is Circuit Closed": { "Type": "Choice", "Choices": [ { "Variable": "$.CircuitStatus", "StringEquals": "OPEN", "Next": "Circuit Open" }, { "Variable": "$.CircuitStatus", "StringEquals": "", "Next": "Execute Lambda" } ] }, "Circuit Open": { "Type": "Fail" }
GitHub repository
Per un'implementazione completa dell'architettura di esempio per questo modello, consulta il GitHub repository all'indirizzo. https://github.com/aws-samples/circuit-breaker-netcore-blog