Elaborazione di eventi affidabile con Funzioni di Azure e Hub Eventi

Impara a costruire soluzioni serverless robuste e affidabili utilizzando Funzioni di Azure con trigger Hub eventi di Azure. Questo articolo tratta le migliori pratiche per checkpoint, gestione degli errori e implementazione di pattern di interruttori automatici per assicurarti di non perdere eventi e che le tue applicazioni basate su eventi rimangano stabili e resilienti.

Sfide dei flussi di eventi nei sistemi distribuiti

Si consideri un sistema che invia eventi a una frequenza costante di 100 eventi al secondo. A questo ritmo, più istanze parallele possono elaborare i 100 eventi in ingresso al secondo.

Tuttavia, considerate queste sfide nella fruizione di un flusso di eventi.

  • Un autore di eventi invia un evento danneggiato.
  • Il codice della funzione rileva un'eccezione non gestita.
  • Un sistema downstream passa offline e blocca l'elaborazione degli eventi.

A differenza di un trigger di archiviazione code di Azure, che blocca i messaggi durante l'elaborazione, Hub eventi di Azure legge, per partizione, a partire da un singolo punto nel flusso. Questo comportamento di lettura, più simile a un lettore video, offre i vantaggi desiderati di velocità effettiva elevata, più gruppi di consumer e capacità di riproduzione. Gli eventi vengono letti, in avanti o indietro, da un checkpoint, ma è necessario spostare il puntatore per elaborare nuovi eventi. Per altre informazioni, vedere Checkpoint nella documentazione di Hub eventi.

Quando si verificano errori in un flusso e si sceglie di non avanzare il puntatore, viene bloccata un'ulteriore elaborazione degli eventi. In altre parole, se fermi il puntatore per gestire un problema che elabora un singolo evento, gli eventi non elaborati iniziano ad accumularsi.

La funzione evita i deadlock avanzando sempre il puntatore del flusso, indipendentemente dall'esito positivo o negativo. Poiché il puntatore continua ad avanzare, le funzioni devono gestire correttamente gli errori.

Come il trigger di Event Hubs consuma gli eventi

Funzioni di Azure utilizza gli eventi di un hub eventi eseguendo i passaggi seguenti:

  1. Il trigger crea e mantiene un puntatore in Archiviazione di Azure per ogni partizione dell'hub event.
  2. Il trigger riceve nuovi eventi in un batch (di default), e l'host cerca di attivare la funzione, fornendo il batch di eventi per l'elaborazione.
  3. Quando la funzione termina l'esecuzione, con o senza eccezioni, il trigger avanza il puntatore e salva un checkpoint nell'account di archiviazione predefinito dell'host.
  4. Se le condizioni impediscono l'esecuzione della funzione, l'host non può avanzare il puntatore. Quando il puntatore non può avanzare, le esecuzioni successive elaborano nuovamente gli stessi eventi.

Questo comportamento rivela alcuni punti importanti:

  • Le eccezioni non gestite possono causare la perdita di eventi:

    Le esecuzioni di funzioni che generano un'eccezione continuano a far progredire il puntatore. L'impostazione di un criterio di ripetizione dei tentativi o di un'altra logica di ripetizione dei tentativi ritarda l'avanzamento del puntatore fino al completamento dell'intero tentativo.

  • Funzioni garantisce il recapito at-least-once:

    Il codice e i sistemi dipendenti potrebbero dover tenere conto del fatto che lo stesso evento potrebbe essere elaborato due volte. Per altre informazioni, vedere Progettare le Funzioni di Azure per un input identico.

  • Lo stato del checkpoint è memorizzato in Archiviazione di Azure:

    Il trigger salva in modo persistente il checkpoint (puntatore di elaborazione) nell'account di archiviazione configurato tramite l'impostazione AzureWebJobsStorage dell'app per le funzioni. Questo riferimento al checkpoint memorizzato significa:

    • Quando cambi AzureWebJobsStorage per fare riferimento a un account di archiviazione diverso, la funzione inizia a elaborare da una nuova posizione, il che può portare a riprocessare eventi.
    • Quando un hub eventi viene eliminato e ricreato, la posizione del flusso di eventi (come numeri di sequenza e offset) viene resettata mentre i riferimenti dei checkpoint memorizzati rimangono invariati. In questo scenario, la funzione potrebbe non elaborare nuovi eventi finché il checkpoint non viene cancellato manualmente.

Gestione delle eccezioni

Anche se tutto il codice della funzione deve includere un blocco try/catch al massimo livello di codice, la presenza di un catch blocco è ancora più importante per le funzioni che usano eventi di Event Hubs. In questo modo, quando viene generata un'eccezione, il blocco catch gestisce l'errore prima che il puntatore progredisca.

Meccanismi e criteri di ripetizione dei tentativi

Poiché molte eccezioni nel cloud sono temporanee, il primo passaggio nella gestione degli errori consiste sempre nel ripetere l'operazione. È possibile applicare criteri di ripetizione dei tentativi predefiniti o definire la logica di ripetizione dei tentativi.

Criteri di ripetizione dei tentativi

Funzioni fornisce criteri di retry predefiniti per Hub eventi. Quando si utilizzano i criteri di ripetizione, è sufficiente generare una nuova eccezione e l'host tenta di elaborare nuovamente l'evento in base al criterio definito. Questo comportamento di ripetizione dei tentativi richiede la versione 5.x o successiva dell'estensione di Hub eventi. Per altre informazioni, vedere il Criteri di ripetizione dei tentativi.

Logica di ripetizione dei tentativi personalizzata

È anche possibile definire la logica di ripetizione dei tentativi nella funzione stessa. Ad esempio, è possibile implementare un criterio che segue un flusso di lavoro illustrato dalle regole seguenti:

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

Annotazioni

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

Errori non di eccezione

Alcuni problemi possono verificarsi senza che venga generata un'eccezione. Si consideri, ad esempio, un caso in cui si verifica il timeout di una richiesta o l'istanza che esegue la funzione si arresta in modo anomalo. Quando una funzione non viene completata senza un'eccezione, il puntatore di offset non viene mai avanzato. Se il puntatore non avanza, qualsiasi istanza eseguita dopo un'esecuzione non riuscita continua a leggere gli stessi eventi. Questa situazione fornisce una garanzia at-least-once.

La garanzia che ogni evento venga elaborato almeno una volta implica che alcuni eventi potrebbero essere elaborati più volte. Le app per le funzioni devono essere consapevoli di questa possibilità e devono essere compilate in base ai principi di idempotenza.

Gestione degli stati di errore

L'app potrebbe essere in grado di gestire in modo accettabile alcuni errori nell'elaborazione degli eventi. Tuttavia, è necessario essere pronti anche a gestire lo stato di errore persistente, che potrebbe verificarsi a causa di errori nell'elaborazione downstream. In uno stato di errore di questo tipo, ad esempio un archivio dati downstream offline, la funzione deve interrompere l'attivazione degli eventi fino a quando il sistema non raggiunge uno stato integro.

Modello di interruttore

Quando implementi il modello di interruttore , l'app può sospendere efficacemente l'elaborazione degli eventi e quindi riprenderla in un secondo momento dopo la risoluzione dei problemi.

Esistono due componenti necessari per implementare un interruttore in un processo del flusso di eventi:

  • Stato condiviso tra tutte le istanze per tenere traccia e monitorare l'integrità del circuito.
  • Processo primario in grado di gestire lo stato del circuito, come open o closed.

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

Sia Durable Functions che App per la logica di Azure forniscono l'infrastruttura per gestire flussi di lavoro e stati del circuito. Questo articolo descrive l'uso di App per la logica per sospendere e riavviare le esecuzioni delle funzioni, fornendo il controllo necessario per implementare il modello di interruttore.

Definire una soglia di errore tra istanze

Lo stato esterno condiviso persistente è necessario per monitorare l'integrità del circuito quando più istanze elaborano eventi contemporaneamente. È quindi possibile monitorare questo stato persistente in base alle regole che indicano uno stato di errore, ad esempio:

Quando sono presenti più di 100 errori di eventi entro un periodo di 30 secondi in tutte le istanze, interrompere il circuito per interrompere l'attivazione di nuovi eventi.

I dettagli di implementazione per questa logica di monitoraggio variano a seconda delle esigenze specifiche dell'app, ma in generale è necessario creare un sistema che:

  1. Registra i fallimenti su memoria persistente.
  2. Esaminare il conteggio progressivo quando vengono registrati nuovi errori per determinare se è stata raggiunta la soglia di errore dell'evento.
  3. Quando questa soglia viene raggiunta, generare un evento che informa il sistema di interrompere il circuito.

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

App per la logica di Azure include connettori integrati per diversi servizi, funzionalità e orchestrazioni con stato. Gestire lo stato del circuito è una scelta naturale. Dopo aver rilevato quando un circuito deve interrompersi, è possibile compilare un'app per la logica per implementare questo flusso di lavoro:

  1. Attivare un flusso di lavoro di Griglia di eventi che arresta l'elaborazione della funzione.
  2. Inviare un messaggio di posta elettronica di notifica che include un'opzione per riavviare il flusso di lavoro.

Per imparare a disabilitare e riabilitare funzioni specifiche usando le impostazioni dell'app, consulta Come disabilitare funzioni in Funzioni di Azure.

Il destinatario dell'email può indagare sullo stato del circuito e, quando opportuno, riavviarlo tramite un link nell'email di notifica. Quando il flusso di lavoro riavvia la funzione, elabora gli eventi dall'ultimo checkpoint dell'hub eventi.

Quando usi questo approccio, non perdi eventi, processi gli eventi in ordine e puoi interrompere il circuito finché serve.

Strategie di migrazione per i trigger di Griglia di eventi

Quando si esegue la migrazione di un'app per le funzioni esistente tra aree o tra alcuni piani, è necessario ricreare l'app durante il processo di migrazione. In questo caso, durante il processo di migrazione, potresti avere due app che possono consumare dallo stesso flusso di eventi e scrivere nella stessa destinazione di output.

Per evitare la perdita o la duplicazione di dati degli eventi durante il processo di migrazione, considera di utilizzare gruppi di consumatori:

  1. Creare un nuovo gruppo di consumer per la nuova app di destinazione.

  2. Configurare il trigger nella nuova app per usare questo nuovo gruppo di consumatori.

    Utilizzando questo approccio, entrambe le app possono elaborare eventi in modo indipendente durante la validazione.

  3. Verificare che la nuova app stia elaborando correttamente gli eventi.

  4. Ferma l'app originale o rimuovi l'abbonamento o il gruppo di consumatori.