java - Consistencia de datos en transacciones XA
oracle jboss (4)
Desafortunadamente las transacciones XA no soportan la consistencia. Cuando se asigna a CAP, el teorema XA resuelve la disponibilidad y la tolerancia de partición en múltiples almacenes de datos. Al hacerlo, debe sacrificarse en Consistencia. Cuando usas XA tienes que abrazar la consistencia eventual.
En cualquier caso, crear sistemas que sean CP o AP es tan difícil que, independientemente de su almacén de datos o modelo transaccional, enfrentará este problema.
Supongamos que tenemos una base de datos (por ejemplo, Oracle) y un proveedor de JMS (por ejemplo, HornetQ) que participa en una transacción XA. Se envía un mensaje a una cola JMS y algunos datos se conservan en la base de datos en la misma transacción distribuida. Una vez confirmada la transacción, un consumidor de mensajes leerá los datos persistentes y los procesará en una transacción separada.
Con respecto a la primera transacción XA, la siguiente secuencia de eventos puede ser ejecutada por el administrador de transacciones (por ejemplo, JBoss)
- preparar (HornetQ)
- preparar (Oracle)
- cometer (HornetQ)
- cometer (Oracle)
¿Qué sucede si el consumidor de mensajes comienza a leer los datos después de completar la confirmación en HornetQ, pero aún se está ejecutando en Oracle? ¿El consumidor de mensajes leerá datos obsoletos?
La pregunta puede generalizarse a cualquier tipo de recursos múltiples que participan en transacciones XA, es decir, existe la posibilidad de una pequeña ventana de tiempo (cuando se ejecutan las fases de confirmación) en la que un lector de otra transacción concurrente puede obtener un estado incoherente (al leer confirmado datos de un recurso y datos obsoletos de otro)?
Yo diría que la única forma en que los recursos transaccionales pueden evitar esto es bloquear a todos los lectores de datos afectados una vez que se complete la fase de preparación hasta que se emita la confirmación. De esta manera, el ejemplo de consumidor de mensajes mencionado anteriormente se bloquearía hasta que los datos se confirmen en la base de datos.
Insertaré un campo de estado, por lo que después de cada paso, si fue exitoso, el estado se actualizará, y el lector debe verificar el estado antes de realizar una operación.
Sí. Es posible que un sistema externo reciba y consuma los mensajes que envía antes de que realmente se confirme la base de datos, incluso si la transacción falla y luego se retrotrae.
Durante los últimos dos años he estado realizando el mantenimiento y desarrollo de un sistema distribuido utilizando transacciones XA con WebSphere MQ como proveedor de JMS y Oracle 11g como base de datos de respaldo.
Uno de sus trabajos por lotes leería los mensajes fuera de línea de la base de datos, los enviaría a JMS y los marcaría como enviados en la base de datos, todo como parte de la misma transacción XA. Si alguno de los mensajes o el DB fallaran, la transacción se revertiría.
Algunas veces, un mensaje sería demasiado grande para JMS y causaría que el envío () fallara y la transacción completa se deshaga (), dejando el DB sin cambios.
Sin embargo , un consumidor externo todavía estaba recibiendo y procesando cada mensaje enviado antes de la reversión. Lo sabía porque me enviarían un correo electrónico por cada mensaje procesado, y recibía muchos correos electrónicos sobre mensajes que no estaban marcados como enviados en la base de datos (porque la transacción se había revertido).
Si este sistema externo tuviera que SELECCIONAR CUENTA (*) la cantidad de mensajes enviados por mi sistema, leería 0 mensajes enviados, a pesar de que ya ha consumido cientos de ellos.
Entonces, sí, es posible que un sistema externo lea datos obsoletos incluso cuando se utilizan transacciones XA.
Tengo un poco de experiencia con un poco de entorno diferente basado en Weblogic JMS y Oracle 11g. En esta respuesta supongo que funciona exactamente igual. Espero que mi respuesta te ayude.
En nuestro caso, existía un sistema "distante" que era obligatorio notificar según los diferentes eventos ocurridos dentro del sistema local. El otro sistema también está en rojo en nuestra base de datos, por lo que el caso de uso parece casi idéntico a su problema. La secuencia de los eventos fue exactamente la misma que la tuya. En los sistemas de prueba no había un solo faulire. Todos pensaron que funcionará, pero algunos de nosotros dudamos si es la solución correcta. A medida que el software llega a la producción, algunos de los procesos BPM se ejecutan de manera impredecible. Así que una respuesta simple a su pregunta: sí, es posible y todos deben ser conscientes de ello.
Nuestra solución (en mi opinión) no fue bien planificada, pero reconocimos que la pequeña ventana de tiempo entre los dos intentos es frenar el sistema, por lo que agregamos un poco de "retraso" a la cola (si recuerdo que fue como 1- 2 minutos). Fue suficiente para terminar el otro compromiso y leer datos consistentes. Desde mi punto de vista no es la mejor solución. No está resolviendo el problema de sincronización (¿qué sucede si una transacción de Oracle es más larga que 1-2mins?).
Here hay una excelente publicación de blog que vale la pena leer y la última solución me parece la mejor. Lo implementamos en otro sistema y está funcionando mejor. Es importante tener en cuenta que debe limitar los reintentos (lecturas) para evitar que los subprocesos se "atasquen". (Con algunos informes de errores). Con estas restricciones no pude encontrar una mejor solución hasta el momento, por lo que si alguien tiene una opción mejor, espero escucharla. :)
Edición: errores tipográficos.