2015-09-10 12 views
14

Sono molto nuovo per Amazon Kinesis così forse questo è solo un problema nella mia comprensione, ma nel AWS Lambda FAQ si dice:Amazon AWS Kinesis & Lambda Tentativi

L'Amazzonia Kinesis e DynamoDB Corsi d'acqua record inviati alla tua funzione AWS Lambda sono rigorosamente serializzati, per frammento. Ciò significa che se metti due record nello stesso frammento, Lambda garantisce che la tua funzione Lambda verrà invocata con successo con il primo record prima di essere invocata con il secondo record. Se l'invocazione per un record è scaduta, viene limitata o si verificano altri errori, Lambda riproverà fino a quando non riesce (o il record raggiunge la scadenza di 24 ore) prima di passare al record successivo. L'ordinamento dei record su diversi frammenti non è garantito e l'elaborazione di ogni frammento avviene in parallelo.

La mia domanda è, che cosa succede se per qualche motivo alcuni dati malformati viene messo su un frammento da un produttore e quando la funzione Lambda lo raccoglie esso errori fuori e poi continua a riprovare costantemente? Ciò significa quindi che l'elaborazione di quel particolare frammento sarebbe stata bloccata per 24 ore dall'errore.

È la pratica migliore per gestire errori di applicazione del genere avvolgendo il problema in un errore personalizzato e inviando questo errore a valle insieme a tutti i record elaborati correttamente e lasciando che sia il consumatore a gestirlo? Ovviamente, questo non sarebbe ancora d'aiuto nel caso di un errore irreversibile che ha fatto crashare il programma come un puntatore nullo: di nuovo saremmo tornati al ciclo di tentativi di blocco per le prossime 24 ore.

risposta

23

Non pensarci troppo, il Kinesis è solo una coda. Devi consumare un record (es. Pop dalla coda) con successo per poter passare a quello successivo. Proprio come uno stack FIFO.

L'approccio appropriata dovrebbe essere:

  • Ottenere un record dal flusso.
  • Elaboralo in un blocco try-catch-finally.
  • Se il record viene elaborato correttamente, nessun problema. < - TRY
  • Ma se non funziona, annotarlo in un altro punto per esaminare il motivo perché non è riuscito. < - CATCH
  • E alla fine dei blocchi logici, mantenere sempre la posizione su DynamoDB. < - FINALMENTE
  • Se si verifica un errore interno nel sistema (errore di memoria, errore hardware ecc.), Si tratta di un'altra storia; in quanto potrebbe influire sull'elaborazione di tutti i record , non solo su uno.

A proposito, se l'elaborazione di un record richiede più di 1 minuto, è ovvio che stai facendo qualcosa di sbagliato. Poiché Kinesis è progettato per gestire migliaia di record al secondo, non dovresti avere il lusso di elaborare lavori così lunghi per ognuno di essi.

La domanda che si pone è un problema generale dei sistemi di coda, a volte chiamato "messaggio velenoso". Devi gestirli nella tua logica aziendale per essere al sicuro.

http://www.cogin.com/articles/SurvivingPoisonMessages.php#PoisonMessages

+0

Sembra ragionevole, ma solo una breve domanda sul bit DynamoDb, perché devo mantenere la posizione (presumo intendete il numero di sequenza)? – Stefano

+0

Perché quando si interrompe un nodo "Kinesis Consumer Application" e si avvia successivamente; dovresti essere in grado di continuare dall'ultimo punto che eri. – az3

+0

Ah sì, questo ha senso. – Stefano

14

Questa è una domanda comune sulla elaborazione degli eventi in Kinesis e cercherò di darvi alcuni punti per costruire la vostra funzione Lambda per gestire tali problemi con i dati "corrotti". Poiché è buona pratica che parti separate del sistema vengano scritte nello stream di Kinesis e in altre parti che leggono dallo stream di Kinesis, è normale che si abbiano tali problemi.

Primo, perché si verificano tali eventi problematici?

L'utilizzo di Kinesis per elaborare gli eventi è un buon modo per suddividere un sistema complesso che esegue sia l'elaborazione front-end (che serve gli utenti finali), sia l'elaborazione back-end di codice/allo stesso tempo (analizzando gli eventi), in due parti indipendenti del tuo sistema. Le persone front-end possono concentrarsi sulla propria attività, mentre le persone di back-end non hanno bisogno di spingere le modifiche del codice al front-end, se vogliono aggiungere funzionalità per servire i loro casi d'uso analitici. Kinesis è un buffer di eventi che interrompe entrambi la necessità di sincronizzazione e semplifica il codice di logica aziendale.

Pertanto, vorremmo eventi scritti nel flusso di essere flessibili nella loro "schema", e se le squadre di front-end desiderano cambiare il formato dell'evento, aggiungere campi, eliminare i campi, modificare il protocollo o la chiavi di crittografia, dovrebbero essere in grado di farlo tutte le volte che vogliono.

Ora spetta ai team che stanno leggendo dal flusso di essere in grado di elaborare tali eventi flessibili in modo efficiente, e non interrompere il loro trattamento ogni volta che tale cambiamento sta accadendo. Pertanto, dovrebbe essere comune che la funzione Lambda visualizzerà eventi che non è in grado di elaborare e "poison-pill" non è un evento raro come ci si potrebbe aspettare.

Secondo, come gestisci tali eventi problematici?

La funzione Lambda riceverà un lotto di eventi da elaborare. Si prega di notare che non si dovrebbero ottenere gli eventi uno per uno, ma in grandi lotti di eventi. Se i tuoi batch sono troppo piccoli, otterrai rapidamente ritardi nel flusso.

Per ogni batch si itererà sugli eventi, li elaborerà e quindi si verificherà in DynamoDB l'ultimo ID di sequenza del batch. Lambda sta facendo la maggior parte di questi passi automaticamente (vedere di più qui: http://docs.aws.amazon.com/lambda/latest/dg/walkthrough-kinesis-events-adminuser-create-test-function.html):

console.log('Loading function'); 

exports.handler = function(event, context) { 
    console.log(JSON.stringify(event, null, 2)); 
    event.Records.forEach(function(record) { 
     // Kinesis data is base64 encoded so decode here 
     payload = new Buffer(record.kinesis.data, 'base64').toString('ascii'); 
     console.log('Decoded payload:', payload); 
    }); 
    context.succeed(); 
}; 

Questo è ciò che sta accadendo nel "percorso felice" , se tutti gli eventi vengono elaborati senza alcun problema. Ma se si incontrano problemi nel batch e non si "commit" gli eventi con la notifica di esito positivo, il batch avrà esito negativo e si otterranno di nuovo tutti gli eventi nel batch.

Ora è necessario decidere qual è il motivo dell'errore nell'elaborazione.

  • temporanea problema (throttling, problema di rete ...) - è ok per aspettare un secondo e riprovare per un paio di volte. In molti casi il problema si risolverà da solo.

  • Occasional Problema (memoria insufficiente ...) - è preferibile aumentare l'allocazione di memoria della funzione Lambda o ridurre la dimensione del batch. In molti casi tale modifica risolverà il problema.

  • costante fallimento - significa che si deve ignorare l'evento problematico (metterlo in una DLQ - dead-letter-coda) o modificare il codice per gestire la cosa.

Il problema è identificare il tipo di errore nel codice e gestirlo in modo diverso. Devi scrivere il tuo codice Lambda in un modo per identificarlo (tipo di eccezione, ad esempio) e reagire in modo diverso.

È possibile utilizzare l'integrazione con CloudWatch per scrivere tali errori sulla console e creare gli allarmi pertinenti. È possibile utilizzare i registri di CloudWatch anche come modo per registrare la "coda di messaggi non recapitabili" e vedere qual è la fonte del problema.

+1

Come gestite se * alcuni * degli eventi in un batch sono riusciti, ma altri non sono riusciti? Considera un lambda che invia un'email usando SES per ogni evento che riceve. Potrei ottenere un lotto di 100 eventi e inviare correttamente le prime 20 email, ma SES ha un'interruzione per il resto del tempo. Voglio segnalare un successo dei primi 20 eventi (in modo da non inviare spam alle persone), ma voglio riprovare questi ultimi 80. È possibile? –

+0

È possibile gestire un elenco con funzionalità di ricerca per evitare duplicazioni. Puoi utilizzare la tabella DynamoDB con la chiave come email e il valore dell'ultima email inviata. Un'altra soluzione comune è l'uso di Redis in ElastiCache con un TTL delle chiavi di e-mail. Prima di inviare un'e-mail, si controlla quando è stata inviata l'ultima volta che l'e-mail è stata inviata e si aggiorna il record su ogni invio andato a buon fine. – Guy

+0

Sto affrontando lo stesso scenario @CamJackson. DynamoDB ora supporta TTL che potrebbe essere utile per questo –