Arquitectura Orientada a Eventos

Introducción

En esta entrada vamos a hablar sobre arquitectura orientada a eventos y async api.

Recalcar que este artículo se trata de una aproximación mía personal basada en diversos artículos, libros y conferencias que he estado consultando estos meses.

Partamos desde el principio ¿Qué es la arquitectura orientada a eventos?. Si partimos de nuestra querida amiga wikipedia tenemos que:

Es es un patrón de arquitectura software que promueve la producción, detección, consumo de, y reacción a eventos

De esta definición nos quedamos con varios conceptos:

Evento

Vamos a entender como evento cualquier cambio significativo e interesante que se ha producido en el sistema. El evento representa algo que ya ha sucedido en el mundo real, no incluye cosas que van a pasar en un futuro. Los eventos viajan en una sola dirección, es decir no esperan una respuesta lo que se denomina “fire and forget”.

Los eventos son inmutables, no cambian ni se alteran. Un estado puede corresponder a la creación, cambio del estado de una entidad, etc.

Un evento generalmente contiene toda la información necesaria para describir el evento, y suele estar en un formato JSON, aunque podría estar en otros formatos.

Un evento puede llevar información adicional que sea posteriormente proporcionada a aquel que la consuma, a esta información adicional se la denomina payload.

Productores o publicadores

Vamos a distinguir en esta arquitectura los productores, cuando se produce un evento en una aplicación productora publicará un evento o comando, este será publicado en un broker de mensajes. Una vez publicado el evento, el productor se desentiende de qué ocurra con el mensaje.

Consumidores o suscriptores

En el broker en el que son publicados los eventos pueden estar suscritas diversas aplicaciones, estas aplicaciones estarán a la escucha de cuando se produzca un evento, recibir el evento con su payload y con este mensaje recibido realizar la lógica para la que se hayan programada.

Comandos

Aunque no aparecen en la definición también quiero hablar de los comandos. Los comandos son acciones, peticiones para operaciones futuras que deben realizar cambios en el sistema. Estos comandos pueden pasar por diversos estados así como producir error. Suelen ser acciones que se desea que ocurra en el sistema.

Broker de mensajería

Se trata de una tecnología dedicada a procesar e intercambiar mensajes de datos entre aplicaciones. Son un mediador entre sistemas que no tienen por qué conocerse mutuamente. Esta característica permite reducir el acoplamiento y escalar de una forma simple y eficiente.

Para ello hace uso un patrón de mensajería en el cuál tenemos por un lado como hemos detallado mas arriba publicadores y suscriptores.

Las principales funciones de un broker de mensajería son:

  1. Enrutar los mensajes.
  2. Desacoplar productores de consumidores.
  3. organizar y realizar comprobaciones de los mensajes.
  4. Almacenar los mensajes.

Idea principal

La idea de esta arquitectura está muy orientada a comunicaciones asíncronas entre distintas aplicaciones. Hasta ahora en una arquitectura orientada a microservicios cuando una aplicación quería comunicarse con otro realizaba una petición mediante un webclient de forma síncrona. También mediante la programación reactiva disponemos de la posibilidad de realizar peticiones mediante un cliente web de forma asíncrona. La arquitectura orientada a eventos nos posibilita establecer comunicaciones entre servicios mediante el patrón de publicadores & suscriptores. Un productor produce un evento o comando, otra aplicación o varias aplicaciones están a la escucha suscritos a este broker y reaccionan como si hubiesen recibido una llamando, realizando a su vez nuevos eventos y desencadenando la lógica deseada.

En esta arquitectura se observa también que además de permitirnos una comunicación entre microservicios, nos permite por otro lado disponer de un log, de conocer qué eventos se han producido, cuando, quien los ha producido, quien los ha recibido, etc. Lo que viene siendo una completa auditoría.

Y finalmente por lo que el hecho de que un evento desencadene una lógica, nos permite mediante una publicación volver a reproducir una lógica que conlleve varias aplicaciones que reaccionen ante dicho evento.

Cuando utilizar Arquitectura Orientada a Eventos

  1. Cuando se desconoce quienes van a ser los consumidores de un evento.
  2. Cuando se requiere que un evento sea consumido por muchos consumidores.
  3. Cuando unos eventos deben desencadenar otros eventos más complejos
  4. Cuando se desea utilizar un patrón CQRS.

Ventajas

  1. Escalabilidad: es posible disponer de varios consumidores de forma que se puedan escalar el consumo de eventos.
  2. Desacoplamiento entre productores y consumidores
  3. Tolerancia a fallos, si se produce una caída de los consumidores, estos pueden recuperar los eventos que tras volver a estar en activo.

Desventajas

  1. Limitado a procesos asíncronos, aunque la arquitectura orientada a eventos está muy enfocado a desacoplar sistemas, las aplicaciones se limitan casi en su totalidad a comunicaciones asíncronas. Aunque es posible realizar comunicaciones síncronas mediante comando, esta arquitectura no está muy enfocado en peticiones y respuestas, ya que son mas complejas de definir y menos eficientes en tiempo de respuesta.
  2. Introducen mayor complejidad: las comunicaciones convencionales de cliente servidor o petición respuesta involucraban dos partes. Ahora tenemos tres partes: productores, broker y consumidores lo cual introduce mayor complejidad a la hora de interaccionar entre todas las partes involucradas.
  3. Enmascaramiento de fallos: cuando los sistemas están fuertemente acoplados un error se propaga de un sistema a otro, llamando la atención y haciéndose notar. En este caso al haber un acoplamiento menor puede ser mas complicado detectar fallos en nuestro sistema. Esto se puede solventar monitorizando y haciendo logs de cada componente orientado a objeto, pero como los anteriores punto, añaden complejidad.

Comunicaciones síncronas

Como hemos indicado más arriba, esta arquitectura está muy orientada a comunicaciones asíncronas entre aplicaciones mediante eventos/comandos. No obstante, aunque los eventos no esperan respuesta es posible establecer comunicación síncrona mediante comandos síncronos.

Esto se realizaría tal y como mostramos en la siguiente imagen:

Captura

La comunicación entre ambas aplicaciones se realiza mediante dos topics o colas de mensajería en una el productor hace una petición que es consumida por el Servicio B y permanece a la espera de una respuesta una vez haya sido recibido el comando y realizado la lógica pertinente. Una vez el Servicio B ha finalizado publica en otro tópico una respuesta.

Como podemos observar es bastante mas complejo que una petición respuesta convencional, y salta a la vista que en tiempo será más elevado al tener que encolarse con otros eventos, y generarse el comando con el correspondiente payload.

Async API

Uno de los problemas que tiene esta arquitectura, al igual que otras es que a medida que crece el número de eventos, productores, consumidores se hace difícil documentar y llevar un seguimiento de qué eventos son producidos y generados. Es por ello que surgen iniciativas como Async API.

Al igual que ocurrió en su momento con los servicios REST y el swagger. Async Api nos propone definir en un formato similar todos los eventos, topics, payloads, consumidores, productores que van a ser participes de nuestra arquitectura. Nos posibilita incluir descripción, ejemplo de los mensajes generados, versionado, seguridad, etc.

Captura

Async Topic Definition

GitHub - fmvilas/topic-definition: AsyncAPI topic structure definition

Una propuestas muy interesante que podemos ver en más detalle en el anterior enlace son unas sencillas reglas a la hora de definir los nombres de los topics en los que publicaremos los mensajes. Estas reglas nos harán mas sencilla tanto la documentación como el mantenimiento de nuestra arquitectura de eventos.

La idea a la hora de poner un nombre de un topic es que siga la siguiente estructura:

Captura

La idea es que a la hora de definir el topic tengamos la siguiente estructura:

  • dominio
  • subdominio
  • versión del topic: inicialmente uno
  • entidad a la que pertenece el evento o comando
    • Si se trata de un evento el nombre del evento que se aplica sobre la entidad que suele ser un verbo en pasado, o sería lo deseable
    • Si se trata de un comando el nombre del comando, que puede ser un verbo en infinito o futuro. Opcionalmente se puede incluir en que estado se encuentra el comando.