Autor: Alejandro Cruz Rojas Sígueme en LinkedIn
Los message brokers se han desarrollado en respuesta a la creciente complejidad de los sistemas distribuidos y la necesidad de una comunicación eficiente y confiable entre aplicaciones. A lo largo de los años, se han desarrollado diversas tecnologías y estándares para abordar estos desafíos. En este contexto, los message brokers desempeñan hoy en día un papel fundamental en la construcción de sistemas escalables y tolerantes a fallos.
Breve historia de los Message Brokers
Década de 1990: Con el crecimiento de la computación distribuida y la necesidad de sistemas más interoperables, se crearon especificaciones y estándares, incluido el «Message Queuing Telemetry Transport (MQTT)» y «IBM MQ Series» (ahora conocido como IBM MQ). Estas tecnologías introdujeron conceptos como colas de mensajes y sistemas de mensajería centralizados.
Años 2000: Surgieron varios proyectos de código abierto, como Apache ActiveMQ y RabbitMQ, que ofrecían soluciones de mensajería.
Años 2010: La necesidad de procesar datos en tiempo real y manejar flujos de eventos a gran escala llevó al auge de tecnologías de transmisión de datos, como Apache Kafka.
Actualidad: Hoy en día, existen una variedad de message brokers y sistemas de mensajería, tanto propietarios como de código abierto. Algunos ejemplos populares incluyen Apache Kafka, RabbitMQ, Apache ActiveMQ, IBM MQ, AWS SQS, y muchos otros.
El problema
Los componentes de nuestras aplicaciones requieren colaborar entre ellos. Tradicionalmente, esta colaboración se da en la forma de invocaciones síncronas. Esto es, un componente invoca a otro, espera por la respuesta (haciendo nada) y en cuanto recibe esa respuesta, continúa con su siguiente tarea. Sin embargo ¿Qué pasa si el componente invocado tarda en responder?
Consideremos una aplicación distribuida en la que múltiples componentes de distintas aplicaciones interactúan entre sí anidando invocaciones. Una pausa en una invocación generará un efecto multiplicativo en las cadenas de invocación. Esto nos conduce a plantearnos preguntas como: ¿Todas las invocaciones deberían esperar por una respuesta aun cuando las tareas siguientes no requieran los resultados del llamado previo? ¿Hay alguna manera de organizar las tareas para evitar cadenas síncronas de invocaciones? ¿Cómo podríamos manejar invocaciones asíncronas?
Posibles soluciones
Una idea podría ser, implementar invocaciones asíncronas. Un modelo de uso general podría:
- Separar el procesamiento de determinadas tareas en componentes especializados
- Al invocar a un componente de servicio cuya respuesta pueda ser tardada, enviarle como parámetro el componente especializado (callback) que es responsable de procesar el resultado. Esto, sin esperar la finalización de la operación. (Es decir, sin bloqueo).
- Cuando la operación tardada concluya, el componente de servicio, debe invocar al callback que procesará el resultado.
Mejorando la solución con un message broker
Ahora bien, podríamos incorporar un intermediario responsable de conectar, de modo asíncrono y desacoplado, al componente que invoca con el componente de servicio.
Podría funcionar como sigue (aunque podrían existir otras configuraciones distintas):
- El componente solicitante le da al intermediario la solicitud por atender y se olvida de ella
- El intermediario almacena la solicitud en una cola de solicitudes pendientes
- Si existe cualquier componente interesado en responder de alguna manera a la solicitud, le pide al intermediario ser avisado cada vez que haya una nueva solicitud (proceso de inscripción)
- Cada determinado tiempo, el intermediario revisa la cola de solicitudes pendientes y envía, una a una, a cada componente suscrito (opcionalmente puede pedir acuse de recibo por parte de ellos, para controlar la eliminación de una solicitud, de la cola)
- El intermediario va eliminando de la cola cada solicitud transmitida a todos los suscriptores.
- Cada componente suscrito podría, opcionalmente, usar el mismo mecanismo para comunicar el resultado de su procesamiento al invocador o a otros componentes.
El intermediario que acabamos de describir es un message broker.
¿En qué escenarios puede ser útil un message broker?
Hay diversos casos de uso para los message brokers:
- Procesamiento de componentes o aplicaciones que generan altos volúmenes de eventos o datos. Por ejemplo, pensemos en consumir, de manera centralizada, salidas generadas por: a) redes sociales como X, Facebook, etc. , b) dispositivos en aplicaciones de tipo internet de las cosas, c) logs producidos por diversos módulos o aplicaciones en la infraestructura corporativa.
- Colaboración entre microservicios. En un entorno en el que tenemos muchas instancias, de muchos microservicios será preferible tener colaboraciones asíncronas implementadas mediante un message bróker (a este modelo de procesamiento se le conoce como coreografía).
- Tareas de sincronización de datos. Un dato que existe en diversos sistemas o bases de datos, puede cambiar repentinamente. Con un message broker podríamos conectar el proceso que detecta el cambio con las aplicaciones que requieren actualizar ese cambio en sus repositorios y bases de datos locales.
En la figura siguiente se describen algunos otros casos de uso comunes.
Arquitectura de los Message Brokers
Aunque la arquitectura de este tipo de productos puede cambiar de un producto a otro, tenemos componentes que generalmente existen:
- Registro de mensajes. Componente que mediante un API ofrece mecánicas para publicar un mensaje. Dependiendo de lo complejo del message broker puede haber una amplia variedad de funciones de publicación
- Almacenamiento en colas. Los message broker permiten configurar distintos tipos de colas, con comportamientos personalizables respecto de temporalidad, políticas de entrega, políticas de acceso, etc. Generalmente esas colas se pueden asociar a tópicos o temas concretos, de modo que los mensajes puedan organizarse mejor. También es común que haya mecanismos de persistencia asociados a tolerancia a fallos.
- Suscripciones y distribución. Se tienen regularmente componentes para gestionar los suscriptores a determinadas colas o tópicos y distintas políticas de distribución. Por ejemplo, la asignación única de un mensaje a un consumidor o la distribución múltiple. Así mismo se pueden personalizar las políticas de vigilancia del procesamiento por parte de los suscriptores.
- Seguridad. Los message brokers ofrecen mecánicas de autenticación y autorización muy diversas.
- Escalamiento y alta disponibilidad. La mayoría de implementaciones, puede trabajar en clusters y soportar la existencia de instancias redundantes, a fin de soportar altos volúmenes de operación y manejo de incidencias operativas
- Administración y monitoreo. Este componente ofrece por lo general, funcionalidades para rastrear el comportamiento del message broker desde distintas perspectivas.
Conclusiones
- Los message broker son una excelente opción para mejorar el desempeño de infraestructuras aplicativas con altos volúmenes de operación.
- Son piezas de moderada complejidad
- Son tecnologías maduras y tienden a ser confiables
- Se basan en el procesamiento asíncrono y en la implementación de distribución mediante suscripción.