Tengo un sistema Java que usa ActiveMQ para la mensajería. Y el sistema procesa entre 400 y 600 transacciones por segundo y no tenemos problemas cuando todo funciona sin problemas. El sistema también debe enviar estas transacciones a un sistema externo.
Cuando el sistema externo está inactivo por un tiempo prolongado (digamos una o dos horas), lo que hacemos es dejar mensajes fallidos que no se enviaron con éxito al sistema externo durante la interrupción de una cola (lo que llamamos cola de reintento) .
Necesitamos procesar estos mensajes de manera oportuna para que podamos darle al sistema externo suficiente tiempo para recuperarse.
Intentamos varios enfoques y ninguno parece funcionar perfectamente. La mayoría de ellos funcionan cuando tratamos con un menor número de mensajes.
Enfoque n. ° 1: Utilizamos el retardo de ActiveMQ donde configuramos la marca de tiempo en el encabezado JMS (consulte aquí para obtener más detalles: http://activemq.apache.org/delay-and-schedule-message-delivery.html ) y funcionó cuando Hay como unos cientos o miles de mensajes en la cola.
Encontramos pérdida de mensajes cuando había como 500k o más mensajes. Encontramos que los mensajes aparecen misteriosamente sin darnos ninguna pista.
Por ejemplo, veo que los mensajes desaparecieron incluso para 20k mensajes.
Establecemos el retraso en 5 minutos para que los mensajes se prueben hasta 12 veces en una hora. Cuando el sistema externo estuvo inactivo durante una hora, esperábamos que todos los mensajes de 20k fueran reintentados al menos 12 veces.
Lo que observamos fue que cuando consumimos cada 5 minutos:
Intento 1: mensajes de 20k Intento 2: mensajes de 20k
Intento 7: 19987 mensajes Intento 10: 19960 mensajes Intento 12: 19957 mensajes
A veces se procesaron todos los mensajes de 20k pero los resultados de la prueba fueron inconsistentes.
Enfoque # 2:
Utilizamos la política de reenvío de ActiveMQ donde establecemos la política en el nivel de fábrica de conexiones, realizamos la transacción de la sesión, lanzamos una excepción cuando el sistema externo está inactivo, de modo que el intermediario sigue reenviando los mensajes según la configuración de la política de reenvío. Este enfoque tampoco funcionó bien cuando la interrupción dura más tiempo y necesitamos tener consumidores que no bloqueen. Funciona en el nivel de la cola de despacho en sí, forzando la cola cuando hay muchas transacciones entrantes.
Enfoque n. ° 3:
Utilizamos el programador Quartz que se activa cada X minutos y crea conexión, los consumidores reciben mensajes de la cola Reintentar, intentan procesarlos más y, si el sistema externo sigue inactivo, colocan el mensaje fallido en la parte posterior de la cola. Este enfoque tiene muchos problemas que nos obligaron a administrar conexiones, consumidores, etc.
Por ejemplo, cuando hay un par de mensajes en la cola, cuando tenemos más consumidores que el número de mensajes, resulta un mensaje recogido por un consumidor, nuevamente el mismo consumidor deja el mensaje nuevamente en Reintentar (como el sistema externo todavía está inactivo) con otro consumidor recogiéndolo, lo que resulta en un viaje de ida y vuelta del mensaje entre el Consumidor y el Corredor.
Enfoque # 4:
Intentamos almacenar los mensajes fallidos en la base de datos y hacer que el planificador de cuarzo se ejecute cada X minutos para recoger los mensajes de la base de datos.
Esto no está optimizado, ya que implica una gran cantidad de verificación de transacciones entre los consumidores de la base de datos que se ejecutan en varios nodos y la base de datos.
Mi entorno es Java, JBoss, ActiveMQ 5.9, MySQL 5.6 y Spring 3.2.
Revisé varios otros enfoques, como la plantilla de reintento (de Spring) y el patrón de reintento asincrónico con Java 7/8
Mi opinión sobre el tema es que la mayoría de las soluciones funcionan cuando hay una carga mínima y parecen interrumpirse cuando la interrupción dura más o cuando el volumen del mensaje es realmente alto.
Estoy buscando algo donde pueda almacenar y reenviar mensajes fallidos. Para un sistema de 400 TPS, en una hora, puedo tener 1,44 millones de mensajes.
Si el sistema externo está inactivo, entonces, cómo proceso estos 1,44 millones de mensajes, dando a cada mensaje la misma oportunidad de ser reintentado sin perder mensajes o rendimiento.
Estoy buscando una solución dentro del alcance del entorno que tengo.