Riprova progettazione per volumi elevati

8

Ho un sistema Java che utilizza ActiveMQ per la messaggistica. E il sistema elabora da 400 a 600 transazioni al secondo e non abbiamo alcun problema quando tutto procede senza intoppi. Il sistema ha anche potuto inviare queste transazioni a un sistema esterno.

Quando il sistema esterno è inattivo per un periodo di tempo prolungato (ad esempio un'ora o due), ciò che facciamo è che eliminiamo i messaggi non riusciti che non sono stati inviati correttamente al sistema esterno durante l'interruzione di una coda (ciò che chiamiamo Nuovo tentativo).

Dobbiamo elaborare questi messaggi in modo tempestivo in modo da offrire al sistema esterno tutto il tempo necessario per il ripristino.

Abbiamo provato diversi approcci e nessuno sembra funzionare perfettamente. Molti di questi funzionano quando gestiamo un minor numero di messaggi.

Metodo 1: Abbiamo utilizzato il ritardo ActiveMQ in cui abbiamo impostato la data / ora nell'intestazione JMS (vedere qui per ulteriori dettagli: link ) e ha funzionato quando ci sono come poche centinaia o migliaia di messaggi in coda.

Abbiamo rilevato una perdita di messaggi quando c'erano circa 500 o più messaggi. Abbiamo trovato che i messaggi appaiono misteriosamente senza darci alcun indizio.

Ad esempio, vedo che i messaggi sono scomparsi anche per i messaggi 20k.

Impostiamo il ritardo su 5 minuti in modo che i messaggi vengano provati per un massimo di 12 volte in un'ora. Quando il sistema esterno è rimasto inattivo per un'ora, ci aspettavamo che tutti i 20k messaggi fossero riprovati almeno per 12 volte.

Ciò che abbiamo osservato è che quando consumiamo ogni 5 minuti:

Tentativo 1: 20k messaggi Tentativo 2: 20k messaggi

Tentativo 7: 19987 messaggi Tentativo 10: 19960 messaggi Tentativo 12: 19957 messaggi

A volte venivano elaborati tutti i messaggi 20k ma i risultati del test erano incoerenti.

Approccio n. 2:

Abbiamo utilizzato i criteri di riconsegna di ActiveMQ in cui impostiamo il criterio a livello di factory di connessione, rendiamo transazionale la sessione, generiamo un'eccezione quando il sistema esterno è inattivo, in modo che il broker continui a riconsegnare i messaggi in base alla configurazione del criterio di riconsegna. Anche questo approccio non ha funzionato bene quando l'interruzione dura per una durata maggiore e abbiamo bisogno di avere consumatori non bloccanti. Funziona a livello di coda di invio stesso, mettendo a dura prova la coda quando ci sono molte transazioni in entrata.

Approccio n. 3:

Abbiamo usato il programma di pianificazione Quartz che si sveglia ogni X minuti e crea una connessione, i consumatori ottengono i messaggi dalla coda Retry, provano a elaborarli ulteriormente e se il sistema esterno è ancora inattivo, mettono il messaggio fallito sul retro del coda. Questo approccio ha molti problemi tali da costringerci a gestire connessioni, consumatori, ecc.

Ad esempio, quando ci sono un paio di messaggi nella coda, quando abbiamo più consumatori del numero di messaggi, il risultato è stato un messaggio raccolto da un consumatore, di nuovo lo stesso utente che ha scaricato il messaggio in Retry (mentre il sistema esterno è ancora inattivo) con un altro consumatore che lo raccoglie, con conseguente viaggio di andata e ritorno del messaggio tra Consumer e Broker.

Approccio n. 4:

Abbiamo provato a memorizzare i messaggi non riusciti nel DB e fare in modo che lo scheduler del quarzo venga eseguito ogni X minuti per raccogliere i messaggi dal DB.

Questo non è ottimizzato e comporta un sacco di controllo delle transazioni tra gli utenti di DB in esecuzione su più nodi e sul DB.

Il mio ambiente è Java, JBoss, ActiveMQ 5.9, MySQL 5.6 e Spring 3.2.

Sono passato attraverso diversi altri approcci, come Retry template (da Spring) e Asynchronous Retry pattern con Java 7/8

La mia opinione sul problema è che la maggior parte delle soluzioni funziona quando c'è un carico minimo e sembrano interrompersi quando l'interruzione dura più a lungo o quando il volume dei messaggi è molto alto.

Sto cercando qualcosa in cui posso archiviare e inoltrare messaggi non riusciti. Per un sistema 400 TPS, in un'ora, potrei avere 1,44 milioni di messaggi.

Se il sistema esterno non funziona, allora come elaborerò questi 1,44 milioni di messaggi dando a ciascun messaggio la stessa possibilità di essere riproposto senza perdere messaggi o prestazioni.

Sto cercando una soluzione nel campo di applicazione dell'ambiente che ho.

    
posta serverfaces 18.02.2015 - 22:46
fonte

2 risposte

1

Il problema qui è con la limitazione. Quando si presenta il sistema, l'applicazione deve essere progettata in modo tale da non essere sopraffatta sia dal publisher che dal consumatore.

Potresti diventare furbo con il tuo algoritmo. Se si ha la possibilità di classificare un messaggio per priorità, i messaggi non riusciti potrebbero essere salvati con una priorità inferiore. Pertanto, dopo che il publisher ha pubblicato un nuovo messaggio, può esaminare la coda con priorità più bassa per verificare se è necessario ripubblicarli e ripubblicarli.

Questo è un approccio ben noto alla limitazione dei messaggi. Sono sicuro che ci sono altri algoritmi di limitazione che possono essere applicati qui in base alle tue esigenze specifiche.

    
risposta data 30.04.2015 - 23:12
fonte
0

Ecco l'ipotesi ogni nodo ha una coda messaggi e tutti questi nodi utilizzano un solo DB. Tutti questi nodi stanno cercando di inviare messaggi a un sistema esterno.

Un leggero cambiamento nel terzo approccio potrebbe funzionare.

  1. Quando un nodo inizia a creare una tabella per memorizzare solo nuovi messaggi nel caso in cui il sistema esterno si interrompa. Diciamo che node1 ha creato la tabella messages_node1 per archiviare i messaggi.

Ora il caso d'uso è che se i 3 nodi sono in esecuzione all'improvviso, il sistema esterno va giù, quindi ogni nodo dovrebbe memorizzare i nuovi messaggi in arrivo nella tabella corrispondente invece di mettere in coda MQ. Mantenere i messaggi non consegnati nella coda stessa. Quindi non importa quanto tempo impiega il sistema esterno per il ripristino, la coda di messaggistica esistente non verrà caricata. Una volta il nodo capisce che il sistema esterno è attivo, quindi inizia a mettere in coda i messaggi dalla tabella corrispondente.

Questo approccio risolve molti problemi 1. Non dipende dal tempo di recupero del sistema esterno 2.Non si blocca in caso di troppi messaggi in arrivo mentre il sistema esterno è inattivo. 3. La contenzione tra i nodi è ridotta al minimo poiché ogni nodo ha una propria tabella. 4. L'ordine dei messaggi è conservato in una certa misura.

Puoi scrivere API per attivare questi eventi. Qualsiasi correzione con la risposta di approccio sopra

    
risposta data 19.02.2015 - 17:28
fonte

Leggi altre domande sui tag