Está en la página 1de 11

Usando RabbitMQ en cluster con cliente java y spring

La configuración de agrupamiento y alta disponibilidad con RabbitMQ es bastante


simple. Su consola de administración de UI ofrece un buen soporte en el proceso de
monitoreo de clústeres.
RabbitMQ se ha convertido en el software de mensajería más popular, que podemos
ver en las siguientes imágenes de Google Trends a continuación. Aunque está escrito en un
lenguaje no muy popular de Erlang, implementa un protocolo de Message Queue Server
avanzado bastante complejo (AMQP)
La respuesta es que RabbitMQ es un líder en confiabilidad. Tiene un gran soporte
para agrupación, alta disponibilidad y conmutación por error. Todas sus características
están bien documentadas y son fáciles de usar y configurar, incluso si estamos hablando de
mecanismos como el agrupamiento o la alta disponibilidad.
En esta demostración de conceptos, le mostraremos cómo ejecutar algunas
instancias de RabbitMQ proporcionadas en los contenedores Docker en el clúster con colas
de alta disponibilidad (HA). En función de la aplicación Java de ejemplo, veremos cómo
enviar y recibir mensajes del clúster RabbitMQ y veremos cómo este intermediario de
mensajes maneja una gran cantidad de mensajes entrantes.
Aquí hay una imagen que ilustra la arquitectura de la solución presentada.

Usamos el repositorio oficial Docker de RabbitMQ. Aquí hay comandos para


ejecutar tres nodos RabbitMQ. El primer nodo es el maestro del clúster y los otros dos
nodos se unirán a él. Utilizamos la administración de contenedores para habilitar una
consola de administración de UI para cada nodo. Cada nodo tiene puertos de administración
de UI y conexión predeterminados expuestos. Lo importante es vincular los contenedores
rabbit2 y rabbit3 al contenedor rabbit1 , así como rabbit3 a rabbit2 . Es necesario para
unirse al mastering cluster por rabbit1 .

docker run -d --hostname rabbit1 --name rabbit1 -e


RABBITMQ_ERLANG_COOKIE='rabbitcluster' -p 30000:5672 -p 30001:15672 --mount
source=rabbitmqconf,target=/etc/rabbitmq rabbitmq:management

docker run -d --hostname rabbit1 --name rabbit1 -e


RABBITMQ_ERLANG_COOKIE='rabbitcluster' -p 30000:5672 -p 30001:15672 -v
/home/rbartolome/rabbitmq/conf:/etc/rabbitmq/rabbitmq rabbitmq:management
docker run -d --hostname rabbit2 --name rabbit2 --link rabbit1:rabbit1 -e
RABBITMQ_ERLANG_COOKIE='rabbitcluster' -p 30002:5672 -p 30003:15672
rabbitmq:management

docker run -d --hostname rabbit3 --name rabbit3 --link rabbit1:rabbit1 --link rabbit2:rabbit2
-e RABBITMQ_ERLANG_COOKIE='rabbitcluster' -p 30004:5672 -p 30005:15672
rabbitmq:management

Ahora, hay tres instancias de RabbitMQ en ejecución. Podemos ir a la consola de


administración de UI para todas esas instancias disponibles como contenedores
de ventana acoplable, por ejemplo, http://192.168.99.100:30001 ( rabbit1 ). Cada
instancia está disponible en su clúster independiente, como vemos en las imágenes a
continuación. Nos gustaría que todas las instancias funcionen en el mismo grupo, rabbit @
rabbit1 como una agrupación de nodos (También existen tipos diferentes como federación
y pala para este demo utilizaremos la agrupación). Ver distribuyed brokers

Aquí, el conjunto de comandos (agrupación manual con rabbitmqctl.) se ejecuta en


la instancia de rabbit2 para unirse a cluster rabbit @ rabbit1 . El mismo conjunto debe
ejecutarse en el nodo rabbit3 . Al principio, tenemos que conectarnos al contenedor de
Docker y ejecutar un comando Bash. Antes de ejecutar el comando join_cluster
deRabbitMQ , debemos detener el intermediario.
Conectar el nodo 2 con el 1
1. docker exec -i -t rabbit2 \bash
2. root@rabbit2:/# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...
3. root@rabbit2:/# rabbitmqctl join_cluster rabbit@rabbit1
Clustering node rabbit@rabbit2 with rabbit@rabbit1 ...
4. root@rabbit2:/# rabbitmqctl start_app
Starting node rabbit@rabbit2 …
Nodo 3 con 1
1. docker exec -i -t rabbit3 \bash
2. root@rabbit3:/# rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...
3. root@rabbit3:/# rabbitmqctl join_cluster rabbit@rabbit1
Clustering node rabbit@rabbit3 with rabbit@rabbit1 ...
4. root@rabbit3:/# rabbitmqctl start_app
Starting node rabbit@rabbit3 ...
Si todo fue exitoso, deberíamos ver el nombre de cluster rabbit @ rabbit1 en la
esquina superior derecha de la consola de administración de rabbit2 . También debería ver
una lista de nodos en ejecución en la sección Nodos . También puede verificar el estado
del clúster ejecutando cada comando de nodo rabbitmqctl cluster_status , que también
debería mostrar una lista de todos los nodos del clúster.

Después de comenzar, todos los nodos van a la consola de administración de IU en


uno de los nodos. Ahora, vamos a configurar la alta disponibilidad para la cola
seleccionada. No es importante qué nodo elija porque están en un clúster. En
la pestaña Queues, cree una cola con el nombre q.example . Luego, vaya a
la pestaña Admin, seleccione la sección Policies y cree una nueva política.
En la imagen de abajo, puedes ver la política que he creado. Seleccioné ha-mode =
all, lo que significa que se refleja en todos los nodos del clúster y cuando se agrega un
nuevo nodo al clúster, la cola se reflejará en ese nodo. También hay modos de nodos, otro
aspecto de la RabbitMQ high availability. En el campo de patrón, ingrese el nombre de su
cola y seleccione Queues. Si todo fue exitoso, debería ver la característica ha-all en la fila
de la cola.

Una de las mayores ventajas de RabbitMQ es el monitoreo. Puede ver muchas


estadísticas como memoria, uso de disco, estadísticas de E / S, tasas de mensajes detalladas,
gráficos, etc. En las siguientes imágenes, puede ver una comparación de estadísticas de
persistencia para una sola instancia de RabbitMQ (en la parte superior) y tres Instancias
agrupadas (en la parte inferior).
En las siguientes imágenes, tenemos una comparación de las estadísticas de E / S
también para una sola instancia (arriba) y tres instancias agrupadas (abajo).
Y, finalmente, hay imágenes con la visualización de estadísticas de proceso entre
una sola y tres instancias agrupadas. Aquí, pueden ver estadísticas como la memoria y el
uso del disco.
En general, no hay grandes diferencias en las estadísticas entre una sola instancia
independiente y tres instancias agrupadas. Para las pruebas, usé una aplicación de muestra
escrita en Java y Spring que envía mensajes de 100k al intercambio directo y la segunda
aplicación, que escucha los mensajes entrantes en la cola de destino.
El primer pico en cada gráfico presenta el llenado de la cola con mensajes enviados
por el cliente y el segundo pico los representa recibiéndolos de la cola por el oyente del
cliente, aunque no hay una gran diferencia en las estadísticas sobre el servidor RabbitMQ,
podemos observarlos en la aplicación de ejemplo de cliente y oyente.
El envío de 100 mil mensajes a una sola instancia demoró aproximadamente 10
segundos, mientras que el envío a la primera instancia desde el clúster demoró
aproximadamente 54 segundos. También hay una gran diferencia en el procesamiento de
mensajes en el lado del receptor. La recepción de mensajes de una sola cola independiente
demoró aproximadamente 43 segundos, mientras que la recepción de la cola de alta
disponibilidad agrupada tomó aproximadamente 132 segundos.
RabbitMQ tiene un gran soporte en el marco de Spring. Hay muchos proyectos que
utilizan la implementación de RabbitMQ de forma predeterminada, por ejemplo, Spring
Cloud Stream, Spring Cloud Sleuth. Voy a mostrarle una aplicación Spring Boot de
muestra que envía mensajes al clúster RabbitMQ y los recibe de la cola de alta
disponibilidad.
Aquí está la principal clase de aplicación. Habilitamos el escucha de RabbitMQ
declarando @EnableRabbit en la clase y @RabbitListener en el método de
recepción. También tenemos que declarar la cola escuchada, la fábrica de conexiones del
agente y la fábrica de contenedores de escucha para permitir la concurrencia de la escucha.
En el interior CachingConnectionFactory, configuramos las tres direcciones de las
instancias de clúster
RabbitMQ: 192.168.99.100:30000, 192.168.99.100:30002, 192.168.99.100:30004.
En el método de recepción, solo estamos registrando el mensaje entrante en la
consola y contando el tiempo desde el inicio de la aplicación.

@SpringBootApplication
@EnableRabbit
public class Listener {
private static Logger logger = Logger.getLogger("Listener");
private Long timestamp;
public static void main(String[] args) {
SpringApplication.run(Listener.class, args);
}
@RabbitListener(queues = "q.example")
public void onMessage(Order order) {
if (timestamp == null)
timestamp = System.currentTimeMillis();
logger.info((System.currentTimeMillis() - timestamp) + " : " +
order.toString());
}
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new
CachingConnectionFactory();
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");

connectionFactory.setAddresses("192.168.99.100:30000,192.168.99.100:30002
,192.168.99.100:30004");
connectionFactory.setChannelCacheSize(10);
return connectionFactory;
}
@Bean
public SimpleRabbitListenerContainerFactory
rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new
SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setConcurrentConsumers(10);
factory.setMaxConcurrentConsumers(20);
return factory;
}
@Bean
public Queue queue() {
return new Queue("q.example");
}
}

Aquí está la clase principal del remitente:

@SpringBootApplication
public class Sender {
private static Logger logger = Logger.getLogger("Sender");
@Autowired
RabbitTemplate template;
public static void main(String[] args) {
SpringApplication.run(Sender.class, args);
}
@PostConstruct
public void send() {
for (int i = 0; i < 100000; i++) {
int id = new Random().nextInt(100000);
template.convertAndSend(new Order(id, "TEST"+id,
OrderType.values()[(id%2)]));
}
logger.info("Sending completed.");
}
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new
CachingConnectionFactory();
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");

connectionFactory.setAddresses("192.168.99.100:30000,192.168.99.100:30002
,,192.168.99.100:30004");
return connectionFactory;
}
@Bean
public RabbitTemplate template() {
RabbitTemplate rabbitTemplate = new
RabbitTemplate(connectionFactory());
rabbitTemplate.setExchange("ex.example");
return rabbitTemplate;
}
}
Propuesta para la creación de multiples hilos en el grupo de clusters

un grupo dinámico de consumidores, cada uno de ellos con un solo trabajador asociado y
obteniendo de su propio canal de procesos; Es decir, tendremos tantos consumidores y
canales como trabajadores.
a dynamic pool of consumers, each of them with a single associated worker and fetching
from their own broker channel; this is, we will have as many consumer and channels as we
have workers

En conclusión
La configuración de agrupamiento y alta disponibilidad con RabbitMQ es bastante
simple. Rabbit MQ es popular por su soporte en el proceso de monitoreo de clústeres con la
consola de administración de UI. Es fácil de usar e intuitivo.

Otras ventajas
RabbitMQ admite principalmente el intercambio de mensajería basado en cola y asíncrono. Esto
permite al remitente enviar tantos mensajes como sea posible sin importar si se procesan en el destino.

RabbitMQ se puede usar como un almacenamiento de mensajes temporal y un mecanismo de


reintento, y puede escribir su microservicio de manera que para cualquier mensaje no reconocido, el
mensaje se vuelva a intentar hasta que sea procesado o salga de la cola por la fuerza.
Puede diseñar su sistema y usar RabbitMQ como ESB. RabbitMQ admite varias formas diferentes de
enrutar mensajes que pueden aprovecharse para mover mensajes como un ESB.

Referencias:
https://blog.flux7.com/blogs/tutorials/how-to-creating-highly-available-message-
queues-using-rabbitmq
https://www.codeproject.com/Articles/1101424/Create-Microservice-with-Spring-AMQP-
and-RabbitMQ

Crear un canal por hilo, mejores practicas

Como trabaja la persistencia en rabbitMQ y como se configura aquí ver configuración efectiva aquí
ejemplo de archivo de configuración

Advanced erlang config file


Ubicaciones de archivos y directorios en RabbitMQ

Archivo de configuración

Con variables de entorno

Cluster Formation and Peer Discovery Agrupación declarativa desde DNS en el archivo de
configuración:

cluster_formation.peer_disc:overy_backend = rabbit_peer_discovery_dns

cluster_formation.dns.hostname = discovery.eng.example.local (nombre del host master)

También podría gustarte