Qual è l'architettura giusta per la pianificazione e la gestione scalabili di periodici asincroni frequenti?

2

Ho creato un setup che risolve il mio problema, ma ho praticamente hackerato insieme leggendo i documenti AWS e provando le cose, quindi voglio vedere se c'è un modo migliore.

Ai fini di questa discussione definiamo un "compito" come un insieme di processi che 1) raccoglie i dati, 2) elabora i dati e 3) memorizza i dati elaborati. Supponiamo che tutte le attività siano indipendenti, nel senso che ogni attività può essere svolta rispetto allo stato di qualsiasi altra attività. In ogni momento c'è una lista di compiti che devono essere completati in modo asincrono ad intervalli di tempo regolari (per esempio ogni 2 minuti).

Attualmente sto usando quello che chiamerò un modello "una sola operazione per istanza". Ciò significa che ogni 2 minuti uno schedulatore mette ogni attività in lista in una coda e una raccolta di istanze worker letta dalla coda ed esegue le attività dall'inizio alla fine in modo asincrono. Funziona piuttosto bene, ma in rare occasioni mi imbatto in problemi quando un'attività richiede troppo tempo e lega una delle istanze. Inoltre, c'è molto tempo di inattività dopo che un'attività è stata completata (in genere solo 30 secondi o giù di lì) e prima del prossimo ciclo di attività pianificate.

Quindi sto pensando di passare a quello che chiamerò un modello di "catena di montaggio". Ciò significherebbe avere una raccolta di istanze che sono esperti sulla prima parte di un'attività (raccolta di dati), un'altra raccolta che sono esperti sulla seconda parte (elaborazione dei dati) e così via. Specializzando le istanze, la mia speranza è che sarei in grado di ottenere in modo più efficiente la stessa velocità di elaborazione per ogni attività (una volta ogni 2 minuti) e ridurre il rischio di un inceppamento del log se una parte di un'attività richiede troppo tempo. Lo svantaggio principale che posso vedere è che richiederebbe un maggiore coordinamento tra le istanze: le istanze di elaborazione dei dati dovrebbero attendere che le istanze di raccolta dati finiscano e così via. E non ho mai fatto nulla di simile prima, quindi sono preoccupato di ricostruire la mia intera configurazione solo per essere paralizzato da un difetto imprevisto.

Quindi cosa pensa la gente? Ci sono motivi per preferire la catena di montaggio a un compito per istanza? Ci sono modi per migliorare o semplificare entrambi i modelli come l'ho descritto? C'è un modello ancora migliore a cui non ho pensato?

    
posta Paul Siegel 14.03.2016 - 17:52
fonte

3 risposte

1

Due minuti sembrano lunghi.

L'intervallo di tempo è lì per assicurare che tutte le attività vengano completate entro il prossimo round? Se questo è il caso, allora perché non girare un thread o Task per ogni "serie di processi" e semplicemente lasciare che il thread finisca? Il tuo programma di pianificazione potrebbe quindi eseguire, ad esempio, una volta al secondo e utilizzare in modo ottimale le risorse di elaborazione anziché rimanere inattivo per la maggior parte del tempo.

Potresti anche essere interessato a Disruptor, una forma di ring buffer che è specializzata nel tipo di elaborazione che hai descritto, anche se una normale Priority Queue potrebbe essere sufficiente. Il Disruptor ha questo aspetto:

Ulterioriletture
LMax Architecture by Fowler
The LMAX Disruptor

    
risposta data 14.03.2016 - 18:05
fonte
0

Ci sono molti modi per realizzare questo tipo di architettura. Condividono alcune somiglianze (nel senso che esiste un "task manager", possibilmente eseguito in più istanze per affidabilità, e lavoratori, che afferra le attività dal manager), quindi lasciatemi camminare tra i pezzi.

Il core è il "task manager", questo ha una o più code di "articoli disponibili su cui lavorare". Qualsiasi articolo acquisito viene fatto in un "contratto di locazione" (ci torneremo più avanti) e una volta che un lavoratore ha completato un articolo, è contrassegnato come "completato". In genere, gli elementi di lavoro vengono distribuiti "dalla parte anteriore della coda" (utilizzando una sorta di priorità, forse semplice come FIFO) o "a caso" (selezionare qualsiasi elemento).

Un lavoratore inizia leasing di un oggetto di lavoro dal gestore, sbavando verso di esso, quindi (una volta terminato) contrassegnandolo come completo.

Separando il leasing di un oggetto di lavoro (che in pratica significa "viene lavorato su") dal completamento di un oggetto di lavoro, puoi evitare "il lavoratore è morto" o "il lavoratore è inspiegabilmente lento". Anche se l'utilizzo di questa proprietà significa che è necessario assicurarsi che gli elementi di lavoro siano idempotenti (ovvero, non importa se si completa un determinato articolo più di una volta) o assicurarsi che tutto il lavoro svolto sia transazionale, quindi un completamento non riuscito non parte cose a metà.

Puoi quindi utilizzare o vicino a ciò che hai (coda singola) o lasciare che un lavoratore pianifichi "stage n + 1" con il manager, per ottenere più di una catena di montaggio.

Probabilmente vuoi anche una sorta di funzione supervisore, in modo che i lavoratori guasti possano essere riavviati. Questo potrebbe essere parte del task manager o qualcosa di esterno a worker / manager.

    
risposta data 15.03.2016 - 10:24
fonte
0

Non sono sicuro di classificarlo come architettura (ammetto che il termine è un po 'nebuloso). Stai essenzialmente chiedendo come implementare un insieme di compiti ripetuto, a.k.a. un ciclo. Per me questo è più un problema di implementazione.

Penso che l'approccio più semplice sarebbe quello di inviare ogni attività indipendente su un pool di worker e utilizzare un approccio di latch countdown per determinare quando tutti i thread hanno restituito un risultato. Risciacqua e ripeti. Ti consiglio di inserire un acceleratore che garantisca non più di N esecuzioni in un dato intervallo di tempo, quindi impedisci che ciò avvenga se qualcosa va storto.

    
risposta data 15.03.2016 - 17:58
fonte

Leggi altre domande sui tag