2016-06-08 13 views
19

Supponiamo di avere un database (ad esempio Oracle) e un provider JMS (ad esempio HornetQ) che partecipa a una transazione XA. Un messaggio viene inviato a una coda JMS e alcuni dati vengono mantenuti nel database nella stessa transazione distribuita. Dopo il commit della transazione, un utente del messaggio leggerà i dati persistenti e li elaborerà in una transazione separata.Consistenza dei dati nelle transazioni XA

quanto riguarda la prima transazione XA, la seguente sequenza di eventi possono essere eseguiti dal gestore dell'operazione (ad esempio JBoss)

  1. preparare (HornetQ)
  2. preparare (Oracle)
  3. commit (HornetQ)
  4. commit (Oracle)

Cosa succede se il consumatore messaggio inizia la lettura dei dati dopo il commit è completato in HornetQ, ma è ancora in esecuzione in Oracle? Il consumatore del messaggio leggerà i dati obsoleti?

La domanda può essere generalizzata a qualsiasi tipo di più risorse che partecipano alle transazioni XA, ovvero esiste una possibilità per una finestra temporale piccola (quando vengono eseguite fasi di commit) in cui un lettore di un'altra transazione concorrente può ottenere uno stato incoerente (leggendo i dati commessi da una risorsa e i dati obsoleti da un'altra)?

Direi che l'unico modo in cui le risorse transazionali impediscono questo è bloccare tutti i lettori dei dati interessati una volta completata la fase di preparazione fino all'emissione del commit. In questo modo il consumatore di messaggi di esempio sopra menzionato bloccherebbe fino a quando i dati non saranno impegnati nel database.

+0

Buona domanda, è il problema principale con JTA IMO, non è adeguatamente documentato, anche le specifiche sono troppo chiare per descrivere (come dovrebbe) un meccanismo così complesso. –

+0

Inoltre, questo non è il caso di utilizzo peggiore, si pensi ai casi in cui si ha un errore sul commit quando l'implementatore di XAResource non copre il recupero. –

+1

Specifiche dettagliate troppo lunghe per metterle in risposta, ma possono essere trovate in Oracle White Paper ["XA e Oracle Controlled Distributed Transactions"] (http://www.oracle.com/technetwork/products/clustering/overview/distributed -transactions-and-xa-163941.pdf) a pagina 12 nel capitolo "Transazioni distribuite e blocco del database". – ThinkJet

risposta

4

Sfortunatamente le transazioni XA non supportano la coerenza. Quando mappato su CAP theorem XA risolve la tolleranza di disponibilità e partizione su più datastore. In tal modo deve sacrificare su Coerenza. Quando usi XA devi abbracciare la coerenza finale.

In ogni caso, la creazione di sistemi CP o AP è hard enough che, indipendentemente dal datastore o dal modello di transazione, si verificherà questo problema.

1

Ho una certa esperienza con un po 'di ambiente diverso basato su Weblogic JMS e Oracle 11g. In questa risposta suppongo che stia funzionando allo stesso modo . Spero che la mia risposta ti possa aiutare.

Nel nostro caso c'era un sistema "distante" che era obbligatorio notificare in base ai diversi eventi accaduti all'interno del sistema locale. Anche l'altro sistema è rosso nel nostro database, quindi il caso d'uso sembra quasi identico al tuo problema. La sequenza degli eventi era esattamente uguale alla tua. Sui sistemi di test non c'era un solo faulire. Tutti pensavano che funzionasse, ma alcuni di noi dubitavano che fosse la soluzione giusta. Poiché il software ha colpito la produzione, alcuni dei processi BPM sono eseguiti in modo imprevedibile. Quindi una semplice risposta alla tua domanda: sì è possibile e tutti dovrebbero esserne consapevoli.

La nostra soluzione (a mio parere) non era ben pianificata, ma abbiamo riconosciuto che la piccola finestra temporale tra i due commit sta frenando il sistema, quindi abbiamo aggiunto un po 'di "delay" alla coda (se ricorda che era come 1-2 minuti). Era abbastanza per finire l'altro commit e leggere dati coerenti. Dal mio punto di vista non è la soluzione migliore. Non risolve il problema della sincronizzazione (cosa succede se una transazione Oracle è più lunga di 1-2 minuti?).

Here è un ottimo post sul blog che vale la pena leggere e l'ultima soluzione mi sembra la migliore. Lo abbiamo implementato in un altro sistema e funziona meglio. Importante notare che è necessario limitare i tentativi (rilegge) per evitare thread "bloccati". (Con alcuni errori di segnalazione.) Con queste restrizioni non sono stato in grado di trovare una soluzione migliore finora, quindi se qualcuno ha qualche opzione migliore non vedo l'ora di sentirlo.:)

Modifica: errori di battitura.

+0

"e se una transazione oracle è più lunga di 1-2 minuti", il ritardo di cui stiamo parlando è il momento di impegnare il transazione e non l'intera durata della transazione, alcune decine di millisecondi al massimo. Inoltre, i messaggi JMS vengono generalmente inviati sulla rete, il che dovrebbe richiedere più tempo rispetto al commit della seconda fase. Secondo me c'è un altro problema nel tuo design. – Gab

+0

Potrebbe essere risolto più facilmente acquisendo un blocco sui dati letti dal consumatore del messaggio ('seleziona per aggiornamento 'per esempio), che con timeout? Con i timeout, possiamo introdurre una latenza fissa troppo grande per ciascun messaggio o aumentare il rischio di leggere nuovamente i dati non aggiornati se il timeout è troppo basso. –

+0

Un semplice blocco non è un passo avanti come vedo. All'ora di lettura non saranno rappresentati i dati richiesti (l'inserto non è commesso jet). La sincronizzazione manuale che ho citato è (a mio parere) una soluzione più rapida e affidabile. Tornerò dalle vacanze in 2 giorni, se necessario, potrei disegnare un diagramma di flusso. Al telefono le mie possibilità sono piuttosto limitate. – Mark

0

Sì. È possibile che un sistema esterno riceva e consumi i messaggi inviati prima del che il DB effettivamente commette, anche se la transazione fallisce e si ripristina in seguito.

Negli ultimi due anni ho svolto attività di manutenzione e sviluppo di un sistema distribuito utilizzando transazioni XA con WebSphere MQ come provider JMS e Oracle 11g come database di backup.
Uno dei suoi lavori batch leggerebbe i messaggi non in linea dal DB, li invia a JMS e li contrassegna come inviati nel DB - tutto come parte della stessa transazione XA. Se uno dei messaggi o il DB falliva, la transazione verrebbe ripristinata.

Alcune volte, un messaggio sarebbe troppo grande per JMS e causerebbe l'invio di send() e l'intera transazione al rollback(), lasciando invariato il DB.
Tuttavia,, un utente esterno stava ancora ricevendo ed elaborando ogni singolo messaggio inviato prima del rollback. Sapevo perché mi avrebbero mandato un'e-mail per ogni messaggio elaborato, e ricevevo molte e-mail sui messaggi che non erano contrassegnati come inviati nel DB (perché la transazione era stata ripristinata).

Se questo sistema esterno era in qualche modo SELECT COUNT (*) il numero di messaggi inviati dal mio sistema, avrebbe letto 0 messaggi inviati, nonostante ne avessero già consumati centinaia.

Quindi, sì, è possibile che un sistema esterno legga dati non aggiornati anche quando si utilizzano transazioni XA.

0

Inserirò un campo di stato, quindi dopo ogni passaggio, se è stato eseguito correttamente, lo stato verrà aggiornato e il lettore dovrebbe controllare lo stato prima di eseguire un'operazione.

Problemi correlati