Progetta una soluzione accodamento con cluster e più utenti

3

È un problema di progettazione che sto elencando qui.

Ho diverse serie di operazioni commerciali che vengono eseguite per diverse entità aziendali.

Operazioni:

  • Operazione A
  • Operazione B
  • Operazione C

Ad esempio, ho un'entità A. I dati dell'entità A potrebbero essere in parti, ad esempio:

  • Entità A (Jan Data)
  • Entità B (dati febbraio) ecc.

Per completare un caso d'uso, devono essere eseguite tutte le operazioni (A, B, C). Ora queste operazioni sono eseguite e sono indipendenti l'una dall'altra e possono essere eseguite in parallelo, l'unica condizione è che dovrebbero essere di entità diverse. Quindi l'Entità A non può avere tutte le operazioni (A, B o C) in esecuzione in parallelo. E queste operazioni sono in esecuzione sul lato server.

Come ridimensionare questo e fornire una soluzione?

Sto pensando di seguire la soluzione e vorrei avere input dalla comunità su questo.

Penso a tre code per operazioni che ho citato sopra

  • Coda A che esegue l'operazione A
  • coda B che esegue l'operazione B
  • coda C che esegue l'operazione C

E tutti i consumatori ascolteranno queste code.

  • Consumatore A (o più consumatori)
  • Consumatore B (o più consumatori)
  • Consumatore C (o più consumatori)

E il mio server verrebbe bilanciato dal carico e avrò una coda di messaggi singoli contenente queste tre code.

Quindi è possibile che io abbia 2 server in esecuzione e su ogni server ci siano per esempio 5 thread (consumatori) in esecuzione, quindi ci saranno 10 istanze di Consumer A in esecuzione in parallelo a prelevare i dati dalla coda messaggi A.

Come ho affermato in precedenza che per la stessa entità A (che è il caso d'uso aziendale che ho) tutte queste operazioni (Operazione A, Operazione B e Operazione C) non possono essere eseguite in parallelo, dovrebbero essere solo di loro vengono eseguiti.

Quindi quello che penso è avere una voce di database per l'Entità A e tutti i consumatori devono verificare se esiste una voce Database per l'Entità A,

  • se non poi

    1. Crea una voce nel database per l'entità A
    2. Vai ed esegui l'operazione
    3. Rimuovi la voce dal database per l'entità A
  • se c'è una voce nel Database trovata

    1. Accoda nuovamente i dati per l'entità A dalla coda in cui è stata selezionata.

C'è una soluzione migliore possibile per un simile problema di progettazione?

    
posta Abhishek 25.12.2014 - 06:03
fonte

3 risposte

1

È possibile suddividere facilmente i dati con hashing coerente, in questo caso si utilizzerà l'entità come chiave hash. L'hash coerente prende una chiave e un numero di "bucket" come input e ti restituisce il bucket per quella chiave.

Con più server in mente, una soluzione semplice sarebbe quella di selezionare un numero di partizioni in primo piano (diciamo 6), il che significa che avrai 6 code. Quando produci messaggi, calcola il bucket [consistentHash (entity.id, 6)] e metti il messaggio in coda (partizione) che corrisponde a quel bucket. Questo ti dà l'ordine dei messaggi per entità.

Dal punto di vista del consumatore, assicurati semplicemente di avere esattamente un consumatore per coda (partizione). Puoi avere tutti i server che vuoi finché non ci sono consumatori in competizione.

Puoi quindi fare un ulteriore passo avanti all'interno di ogni server per migliorare il parallelismo. Il consumatore di ogni coda (partizione) può essere un router, che prende semplicemente ogni messaggio e fa un altro hash coerente sull'entità, a N bucket in cui N è il numero dei thread di lavoro che vuoi per il parallelismo, quindi passa il messaggio a il thread per il bucket calcolato.

Questa impostazione indirizza i messaggi per la stessa entità in modo coerente allo stesso server e il server instraderà coerentemente il messaggio allo stesso thread di lavoro. Supponendo che i thread N worker siano relativamente alti, ottieni un'eccellente parallelizzazione delle tue attività con l'ordinamento dei messaggi basato su qualsiasi chiave che desideri.

    
risposta data 04.01.2015 - 03:52
fonte
2

Non è necessaria alcuna operazione DB per la sincronizzazione tra le operazioni.

Se sono necessarie tutte e 3 le operazioni da eseguire sui dati in sequenza:

Invia i tuoi dati alla coda A, che ha consumatori che eseguono l'operazione A e alla fine di essa, li manda alla coda B. I consumatori in coda B eseguiranno l'operazione B e invieranno i dati alla coda C dove i consumatori aspetteranno per eseguire l'operazione C su di esso.

Se hai bisogno di tutte e 3 le operazioni da eseguire sui tuoi dati, ma la sequenza non è importante:

Mantieni solo una coda con 10 consumatori per ciascuna operazione (5 su ogni macchina) Aggiungi intestazioni OpA = true, opB = true, opC = true per i tuoi dati quando la aggiungi alla coda per la prima volta. I consumatori per l'operazione A dovrebbero selezionare solo quelli WHERE opA = true. Utilizza Consumatore selettivo per questo ( link ) Quando un consumatore riceve il messaggio, deve eseguire la rispettiva operazione, rimuoverlo rispettiva intestazione e rimanda i dati alla stessa coda (solo se ci sono altre intestazioni dopo aver rimosso la propria intestazione).

    
risposta data 26.12.2014 - 11:05
fonte
2

Questo sembra un caso classico per il modello di ciclo di indirizzamento .

Questo approccio è esattamente come hai descritto: code separate per ogni utente / processore di messaggi. Solo un consumatore può lavorare su un determinato messaggio ( Entity ) alla volta, ma i consumatori sono liberi di lavorare su tutti i messaggi che sono in coda.

Il vantaggio principale di questo approccio è che non devi conoscere la rotta del messaggio quando stai creando il codice. È possibile definire il routing di runtime in base al tipo di messaggio; carico sui singoli consumatori; o qualsiasi cosa abbia un senso per le tue esigenze.

I maggiori vantaggi di questo approccio sono:

  • Ogni consumatore mantiene la sua indipendenza dagli altri consumatori. Un processo consumer di lunga durata può essere integrato singolarmente aggiungendo risorse aggiuntive. Se i tuoi consumatori lo supportano, è possibile aggiungere o spostare risorse aggiuntive in base ai carichi di lavoro correnti.

  • Evitare la necessità di voci del database e blocco. In generale, i DB non gestiscono molto bene i messaggi di eventi su larga scala come questo. Puoi farlo funzionare, ma la soluzione tende a essere fragile e soggetta a rotture quando cambiano i requisiti.

risposta data 26.12.2014 - 02:08
fonte

Leggi altre domande sui tag