Funzioni di Azure l'elaborazione degli eventi affidabile

L'elaborazione degli eventi è uno degli scenari più comuni associati all'architettura serverless. Questo articolo descrive come creare un processore di messaggi affidabile con Funzioni di Azure per evitare di perdere messaggi.

Sfide dei flussi di eventi nei sistemi distribuiti

Prendere in considerazione un sistema che invia eventi a una frequenza costante di 100 eventi al secondo. A questa frequenza, in pochi minuti più istanze di Funzioni parallele possono utilizzare gli eventi in ingresso 100 ogni secondo.

Tuttavia, una delle condizioni meno ottimali seguenti è possibile:

  • Cosa succede se il server di pubblicazione eventi invia un evento danneggiato?
  • Cosa accade se l'istanza di Funzioni rileva eccezioni non gestite?
  • Cosa succede se un sistema downstream è offline?

Come si gestiscono queste situazioni mantenendo la velocità effettiva dell'applicazione?

Con le code, la messaggistica affidabile viene naturalmente fornita. Quando si associa a un trigger funzioni, la funzione crea un blocco nel messaggio della coda. Se l'elaborazione ha esito negativo, il blocco viene rilasciato per consentire a un'altra istanza di ripetere l'elaborazione. L'elaborazione continua quindi fino a quando il messaggio non viene valutato correttamente oppure viene aggiunto a una coda non elaborata.

Anche se un singolo messaggio di coda può rimanere in un ciclo di ripetizione dei tentativi, altre esecuzioni parallele continuano a continuare a dequeuere i messaggi rimanenti. Il risultato è che la velocità effettiva complessiva rimane in gran parte non influenzata da un messaggio non valido. Tuttavia, le code di archiviazione non garantiscono l'ordinamento e non sono ottimizzate per le richieste di velocità effettiva elevate richieste da Hub eventi.

Al contrario, Hub eventi di Azure non include un concetto di blocco. Per consentire funzionalità come velocità effettiva elevata, più gruppi di consumer e capacità di riproduzione, gli eventi di Hub eventi si comportano più come un lettore video. Gli eventi vengono letti da un singolo punto nel flusso per partizione. Dal puntatore è possibile leggere avanti o indietro da tale posizione, ma è necessario scegliere di spostare il puntatore per gli eventi da elaborare.

Quando si verificano errori in un flusso, se si decide di mantenere il puntatore nello stesso punto, l'elaborazione degli eventi viene bloccata fino a quando il puntatore non è avanzato. In altre parole, se il puntatore viene arrestato per gestire i problemi durante l'elaborazione di un singolo evento, gli eventi non elaborati iniziano a accumularsi.

Funzioni di Azure evita i deadlock avanzando il puntatore del flusso indipendentemente dall'esito positivo o negativo. Poiché il puntatore continua a avanzare, le funzioni devono gestire in modo appropriato gli errori.

Come Funzioni di Azure utilizza gli eventi di Hub eventi

Funzioni di Azure usa eventi di Hub eventi durante il ciclo attraverso i passaggi seguenti:

  1. Un puntatore viene creato e persistente in Archiviazione di Azure per ogni partizione dell'hub eventi.
  2. Quando vengono ricevuti nuovi messaggi (in un batch per impostazione predefinita), l'host tenta di attivare la funzione con il batch di messaggi.
  3. Se la funzione completa l'esecuzione (con o senza eccezione) il puntatore avanza e un checkpoint viene salvato nell'account di archiviazione.
  4. Se le condizioni impediscono il completamento dell'esecuzione della funzione, l'host non riesce a completare il puntatore. Se il puntatore non è avanzato, i controlli successivi terminano l'elaborazione degli stessi messaggi.
  5. Ripetere i passaggi da 2 a 4

Questo comportamento rivela alcuni punti importanti:

Gestione delle eccezioni

Come regola generale, ogni funzione deve includere un blocco try/catch al livello massimo di codice. In particolare, tutte le funzioni che usano eventi di Hub eventi devono avere un catch blocco. In questo modo, quando viene generata un'eccezione, il blocco catch gestisce l'errore prima dell'avanzamento del puntatore.

Meccanismi e criteri di ripetizione dei tentativi

Alcune eccezioni sono temporanee e non vengono restituite quando un'operazione viene riprovata in un secondo momento. Questo è il motivo per cui il primo passaggio è sempre quello di ripetere l'operazione. È possibile sfruttare i criteri di ripetizione dei tentativi dell'app per le funzioni o creare la logica di ripetizione dei tentativi all'interno dell'esecuzione della funzione.

L'introduzione di comportamenti di gestione degli errori alle funzioni consente di definire criteri di ripetizione di base e avanzati. Ad esempio, è possibile implementare un criterio che segue un flusso di lavoro illustrato dalle regole seguenti:

  • Provare a inserire un messaggio tre volte (potenzialmente con un ritardo tra i tentativi).
  • Se il risultato finale di tutti i tentativi è un errore, aggiungere un messaggio a una coda in modo che l'elaborazione possa continuare nel flusso.
  • I messaggi danneggiati o non elaborati vengono quindi gestiti in un secondo momento.

Nota

Polly è un esempio di resilienza e libreria di gestione temporanea degli errori per le applicazioni C#.

Errori non eccezioni

Alcuni problemi si verificano anche quando un errore non è presente. Si consideri ad esempio un errore che si verifica al centro di un'esecuzione. In questo caso, se una funzione non completa l'esecuzione, il puntatore di offset non viene mai eseguito. Se il puntatore non avanza, qualsiasi istanza eseguita dopo un'esecuzione non riuscita continua a leggere gli stessi messaggi. Questa situazione fornisce una garanzia "almeno una volta".

La garanzia che ogni messaggio venga elaborato almeno una volta implica che alcuni messaggi possono essere elaborati più volte. Le app per le funzioni devono essere consapevoli di questa possibilità e devono essere compilate intorno ai principi di idempotenza.

Arrestare e riavviare l'esecuzione

Anche se alcuni errori possono essere accettabili, cosa accade se l'app riscontra errori significativi? È possibile arrestare l'attivazione degli eventi fino a quando il sistema raggiunge uno stato integro. La possibilità di sospendere l'elaborazione viene spesso ottenuta con un modello di interruzione del circuito. Il modello di interruzione del circuito consente all'app di interrompere il circuito del processo di evento e riprendere in un secondo momento.

Sono necessari due pezzi per implementare un breaker di circuito in un processo di evento:

  • Stato condiviso in tutte le istanze per tenere traccia e monitorare l'integrità del circuito
  • Processo master che può gestire lo stato del circuito (aperto o chiuso)

I dettagli dell'implementazione possono variare, ma per condividere lo stato tra le istanze è necessario un meccanismo di archiviazione. È possibile scegliere di archiviare lo stato in Archiviazione di Azure, una cache Redis o qualsiasi altro account accessibile da una raccolta di funzioni.

App per la logica di Azure o funzioni durevoli sono una soluzione naturale per gestire lo stato del flusso di lavoro e del circuito. Altri servizi possono funzionare esattamente come, ma le app per la logica vengono usate per questo esempio. Usando le app per la logica, è possibile sospendere e riavviare l'esecuzione di una funzione fornendo il controllo necessario per implementare il modello di interruttore.

Definire una soglia di errore tra istanze

Per tenere conto di più istanze che elaborano gli eventi contemporaneamente, è necessario mantenere lo stato esterno condiviso per monitorare l'integrità del circuito.

Una regola che è possibile scegliere di implementare potrebbe applicare quanto:

  • Se sono presenti più di 100 errori eventuali entro 30 secondi in tutte le istanze, interrompere il circuito e arrestare l'attivazione dei nuovi messaggi.

I dettagli dell'implementazione variano a seconda delle esigenze, ma in generale è possibile creare un sistema che:

  1. Errori di log per un account di archiviazione (Archiviazione di Azure, Redis e così via)
  2. Quando viene registrato un nuovo errore, controllare il conteggio in sequenza per verificare se la soglia viene soddisfatta (ad esempio, più di 100 negli ultimi 30 secondi).
  3. Se la soglia viene soddisfatta, generare un evento per Griglia di eventi di Azure indicare al sistema di interrompere il circuito.

Gestione dello stato del circuito con App per la logica di Azure

La descrizione seguente evidenzia un modo per creare un'app per la logica di Azure per arrestare l'elaborazione di un'app Per le funzioni.

App per la logica di Azure include connettori predefiniti per diversi servizi, funzionalità orchestrazioni con stato e una scelta naturale per gestire lo stato del circuito. Dopo aver rilevato che il circuito deve interrompere, è possibile creare un'app per la logica per implementare il flusso di lavoro seguente:

  1. Attivare un flusso di lavoro griglia di eventi e arrestare la funzione di Azure (con il connettore di risorse di Azure)
  2. Inviare un messaggio di posta elettronica di notifica che include un'opzione per riavviare il flusso di lavoro

Il destinatario del messaggio di posta elettronica può analizzare l'integrità del circuito e, quando appropriato, riavviare il circuito tramite un collegamento nel messaggio di posta elettronica di notifica. Quando il flusso di lavoro riavvia la funzione, i messaggi vengono elaborati dall'ultimo checkpoint dell'hub eventi.

Usando questo approccio, non vengono persi messaggi, tutti i messaggi vengono elaborati in ordine e si può interrompere il circuito purché necessario.

Risorse

Passaggi successivi

Per altre informazioni, vedere le seguenti risorse: