Vuelva a intentar el diseño para alto volumen

8

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.

caras del servidor
fuente

Respuestas:

1

El problema aquí es con la aceleración. Cuando aparece el sistema, la aplicación debe diseñarse de tal manera que no se vea abrumada tanto por el editor como por el consumidor.

Podrías ser inteligente con tu algoritmo. Si tiene la capacidad de clasificar un mensaje por prioridad, entonces los mensajes fallidos podrían guardarse con una prioridad más baja. Entonces, después de que el editor haya publicado un nuevo mensaje, puede buscar en la cola de menor prioridad para verificar si algún mensaje fallido necesita republicarse y volver a publicarse.

Este es un enfoque bien conocido para limitar los mensajes. Estoy seguro de que hay otros algoritmos de aceleración que se pueden aplicar aquí en función de sus necesidades específicas.

codedabbler
fuente
0

Aquí se supone que cada nodo tiene una cola de mensajes y todos estos nodos están usando una base de datos. Todos estos nodos están tratando de enviar mensajes a un sistema externo.

Un ligero cambio en el tercer enfoque puede funcionar.

  1. Cuando un nodo comienza, cree una tabla para almacenar solo mensajes nuevos en caso de que el sistema externo falle. Digamos que node1 ha creado la tabla messages_node1 para almacenar mensajes.

Ahora el caso de uso es si 3 nodos se están ejecutando de repente un sistema externo se cae, entonces cada nodo debe almacenar los mensajes recién llegados a la tabla correspondiente en lugar de hacer cola en MQ. Mantenga los mensajes no entregados en la cola misma. Por lo tanto, no importa cuánto tiempo El sistema externo tarda en recuperarse, la cola de mensajería existente no se cargará. Una vez que el nodo se da cuenta de que el sistema externo está activo, luego comienza a poner en cola los mensajes de la tabla correspondiente.

Este enfoque resuelve muchos problemas 1. No depende del tiempo de recuperación del sistema externo 2. No se bloquea en caso de demasiados mensajes entrantes mientras el sistema externo está inactivo. 3. La contención entre nodos se minimiza ya que cada nodo tiene su propia tabla. 4. La orden de los mensajes se conserva hasta cierto punto.

Puede escribir API para desencadenar estos eventos. Cualquier corrección con la respuesta de enfoque anterior

Amith Manepu
fuente