En este documento, se analizan las diferencias entre las arquitecturas locales controladas por colas de mensajes y las arquitecturas basadas en la nube controladas por eventos que se implementan en Pub/Sub. Intentar aplicar patrones locales directamente a las tecnologías basadas en la nube puede hacer que se pase por alto el valor único que hace atractiva a la nube en primer lugar.
Este documento está dirigido a arquitectos de sistemas que migran diseños de arquitecturas locales a diseños basados en la nube. En este documento, se supone que tienes una comprensión inicial de los sistemas de mensajería.
En el siguiente diagrama, se muestra una descripción general de un modelo de cola de mensajes y un modelo de Pub/Sub.
En el diagrama anterior, se compara un modelo de cola de mensajes con un modelo de transmisión de eventos de Pub/Sub. En un modelo de cola de mensajes, el publicador envía mensajes a una cola en la que cada suscriptor puede escuchar una cola en particular. En el modelo de transmisión de eventos mediante Pub/Sub, el publicador envía mensajes a un tema que los suscriptores pueden escuchar. Las diferencias entre estos modelos se describen en las siguientes secciones.
Compara transmisiones de eventos y mensajería basada en colas
Si trabajas con sistemas locales, ya estás familiarizado con los buses de servicio empresarial (ESB) y las colas de mensajes. Las transmisiones de eventos son un patrón nuevo y existen diferencias importantes con ventajas concretas para los sistemas modernos en tiempo real.
En este documento, se analizan las diferencias clave en el mecanismo de transporte y en los datos de carga útil en una arquitectura controlada por eventos.
Transporte de mensajes
Los sistemas que mueven datos en estos modelos se denominan agentes de mensajes, y hay una variedad de frameworks implementados dentro de ellos. Uno de los primeros conceptos es la mecánica subyacente que transporta los mensajes del publicador al receptor. En los frameworks de mensajes locales, el sistema de origen emite un mensaje explícito, remoto y separado a un sistema de procesamiento posterior mediante una cola de mensajes como transporte.
El diagrama siguiente muestra un modelo de cola de mensajes:
En el diagrama anterior, los mensajes fluyen desde un proceso ascendente del publicador hasta un proceso descendente del suscriptor mediante una cola de mensajes.
El sistema A (el publicador) envía un mensaje a una cola en el agente de mensajes designado para el sistema B (el suscriptor). Si bien el suscriptor de la cola puede constar de varios clientes, todos esos clientes son instancias duplicadas del sistema B que se implementan para el escalamiento y la disponibilidad. Si hay procesos adicionales descendentes (por ejemplo, un sistema C) que deben consumir los mismos mensajes del productor (sistema A), se requiere una cola nueva. Debes actualizar el productor para publicar los mensajes en la cola nueva. Este modelo a menudo se conoce como pase de mensajes.
La capa de transporte de mensajes de estas colas puede proporcionar o no garantías de orden de mensajes. Con frecuencia, se espera que las colas de mensajes proporcionen un modelo de orden garantizado con datos secuenciados en un modelo de acceso en estricto orden de llegada (FIFO), similar a una lista de tareas en cola. Inicialmente, este patrón es fácil de implementar, pero en última instancia presenta desafíos operativos y de escalamiento. A fin de implementar mensajes ordenados, el sistema necesita un proceso central para organizar los datos. Este proceso limita las capacidades de escalamiento y reduce la disponibilidad del servicio, ya que es un punto único de fallo.
Los agentes de mensajería de estas arquitecturas suelen implementar una lógica adicional, como el seguimiento de qué suscriptor recibió los mensajes y la supervisión de la carga del suscriptor. Los suscriptores suelen ser reactivos, sin tener conocimiento del sistema general y solo ejecutar una función cuando reciben los mensajes. Este tipo de arquitecturas se llaman canalizaciones inteligentes (sistema de cola de mensajes) y extremos tontos (suscriptor).
Transporte de Pub/Sub
Al igual que los sistemas orientados a mensajes, los sistemas de transmisión de eventos también transportan mensajes de un sistema de origen a sistemas de destino separados. Sin embargo, en lugar de enviar cada mensaje a una cola orientada por proceso, los sistemas basados en eventos tienden a publicar mensajes en un tema compartido y, luego, uno o más receptores se suscriben a ese tema para detectar temas relevantes.
En el siguiente diagrama, se muestra cómo un publicador ascendente emite un mensaje ascendente en un solo tema y, luego, se enruta al suscriptor descendente que corresponde:
Este patrón de publicación y suscripción es de donde proviene el término pub/sub. Este patrón también es la base del producto de Google Cloud llamado Pub/Sub. En este documento, pubsub se refiere al patrón y Pub/Sub se refiere al producto.
En el modelo pubsub, el sistema de mensajería no necesita conocer ninguno de los suscriptores. No realiza un seguimiento de qué mensajes se recibieron y no administra la carga en el proceso de consumo. En cambio, los suscriptores realizan un seguimiento de qué mensajes se recibieron y son responsables de administrar los niveles de carga y el escalamiento de forma automática.
Un beneficio importante es que, a medida que encuentras usos nuevos de los datos en el modelo de pubsub, no necesitas actualizar el sistema de origen para publicar en colas nuevas ni duplicar datos. En cambio, puedes conectar al consumidor nuevo a una suscripción nueva sin afectar el sistema existente.
Las llamadas en los sistemas de transmisión de eventos son casi siempre asíncronas, envían eventos y no esperan ninguna respuesta. Los eventos asíncronos permiten opciones de escalamiento mayores para el productor y los consumidores. Sin embargo, este patrón asíncrono puede crear desafíos si esperas garantías de orden de mensajes de FIFO.
Datos de la cola de mensajes
En general, los datos que se pasan entre sistemas en sistemas de cola de mensajes y los sistemas basados en pubsub se denominan mensaje en ambos contextos. Sin embargo, el modelo en el que se presentan los datos es diferente. En los sistemas de cola de mensajes, los mensajes reflejan un comando destinado a cambiar el estado de los datos descendentes. Si observas los datos de los sistemas de cola de mensajes locales, el publicador puede indicar de forma explícita lo que debe hacer el consumidor. Por ejemplo, un mensaje de inventario podría indicar lo siguiente:
<m:SetInventoryLevel>
<inventoryValue>3001</inventoryValue>
</m: SetInventoryLevel>
En este ejemplo, el productor le indica al consumidor que necesita establecer el nivel de inventario en 3001. Este enfoque puede ser desafiante porque el productor necesita comprender la lógica empresarial de cada consumidor y debe crear estructuras de mensajes separadas para diferentes casos de uso. Este sistema de cola de mensajes era una práctica común con las aplicaciones monolíticas grandes que la mayoría de las empresas implementaban. Sin embargo, si deseas moverte más rápido, innovar y escalar más que antes, estos sistemas centralizados pueden convertirse en un cuello de botella porque el cambio es riesgoso y lento.
Este patrón también presenta desafíos operativos. Cuando hay datos incorrectos, registros duplicados u otros problemas y se deben corregir, este modelo de mensajería presenta un desafío significativo. Por ejemplo, si necesitas revertir el mensaje que se usó en el ejemplo anterior, no sabes qué configurar como valor corregido, ya que no tienes referencia al estado anterior. No tienes estadísticas sobre si el valor de inventario era 3,000 o 4,000 antes de que se enviara ese mensaje.
Datos de pubsub
Los eventos son otra forma de enviar datos de mensajes. Lo que es único es que los sistemas controlados por eventos se enfocan en el evento que ocurrió en lugar del resultado que debe ocurrir. En lugar de enviar datos que indiquen qué acción debe realizar un consumidor, estos se enfocan en los detalles del evento real producido. Puedes implementar sistemas basados en eventos en una variedad de plataformas, pero con frecuencia se ven en sistemas basados en pubsub.
Por ejemplo, un evento de inventario podría verse de la siguiente manera:
{ "inventory":-1 }
Los datos del evento anterior indican que ocurrió un evento que redujo el inventario en 1. Los mensajes se enfocan en el evento que ocurrió en el pasado y no en un estado que se cambiará en el futuro. Los publicadores pueden enviar mensajes de forma asíncrona, lo que hace que los sistemas controlados por eventos sean más fáciles de escalar que los modelos de cola de mensajes. En el modelo pubsub, puedes separar la lógica empresarial para que el productor solo necesite comprender las acciones realizadas en ella y no necesite comprender los procesos descendentes. Los suscriptores de esos datos pueden elegir la mejor manera de manejar los datos que reciben. Debido a que estos mensajes no son comandos imperativos, el orden de los mensajes se vuelve menos importante.
Con este patrón, es más fácil revertir cambios. En este ejemplo, no se necesita información adicional porque puedes anular el valor del inventario para moverlo en la dirección opuesta. Los mensajes que llegan tarde o están desordenados ya no son una preocupación.
Comparación de modelos
En este caso, tienes cuatro elementos del mismo producto en tu inventario. Un cliente muestra un recuento del producto, y el siguiente compra tres recuentos de ese mismo producto. En esta situación, supongamos que el mensaje para el producto que se muestra se retrasó.
En la siguiente tabla, se compara el nivel de inventario del modelo de cola de mensajes que recibe el recuento de inventario en el orden correcto con el mismo modelo que recibe el recuento de inventario fuera de orden:
Cola de mensajes (orden correcto) | Cola de mensajes (desordenada) |
---|---|
Inventario inicial: 4 |
Inventario inicial: 4 |
Mensaje 1: setInventory(5) |
Mensaje 2: setInventory(2) |
Mensaje 2: setInventory(2) |
Mensaje 1: setInventory(5) |
Nivel de inventario: 2 |
Nivel de inventario: 5 |
En el modelo de cola de mensajes, el orden en el que se reciben los mensajes es importante porque el mensaje contiene el valor calculado previamente. En este ejemplo, si los mensajes llegan en el orden correcto, el nivel de inventario es 2. Sin embargo, si los mensajes llegan de forma desordenada, el nivel de inventario es 5, lo que es inexacto.
En la siguiente tabla, se compara el nivel de inventario del sistema basado en pubsub que recibe el recuento de inventario en el orden correcto con el mismo sistema que recibe el recuento de inventario fuera de orden:
Pubsub (orden correcto) | Pubsub (desordenado) |
---|---|
Inventario inicial: 4 | Inventario inicial: 4 |
Mensaje 2: "inventory":-3 |
Mensaje 1: "inventory":+1 |
Mensaje 1: "inventory":+1 |
Mensaje 2: "inventory":-3 |
Nivel de inventario: 2 |
Nivel de inventario: 2 |
En el sistema basado en pubsub, el orden de los mensajes no importa porque lo informan los servicios que producen eventos. Sin importar el orden en que lleguen los mensajes, el nivel de inventario es preciso.
El siguiente diagrama muestra cómo en el modelo de cola de mensajes, la cola ejecuta comandos que indican al suscriptor cómo debe cambiar el estado mientras está en el modelo pubsub, los suscriptores reaccionan a los datos de eventos que indican lo que ocurrió en el publicador:
Implementa arquitecturas controladas por eventos
Hay una variedad de conceptos que debes tener en cuenta cuando implementas arquitecturas controladas por eventos. En las siguientes secciones, se presentan algunos de esos temas.
Garantías de entrega
Un concepto que aparece en un debate sobre el sistema es la confiabilidad de las garantías de entrega de mensajes. Los distintos proveedores y sistemas pueden proporcionar diferentes niveles de confiabilidad, por lo que es importante comprender las variaciones.
El primer tipo de garantía hace una pregunta simple: si se envía un mensaje, ¿se garantiza su entrega? Esto se conoce como entrega al menos una vez. Se garantiza que el mensaje se entregará al menos una vez, pero se puede enviar más de una vez.
Un tipo diferente de garantía es la entrega como máximo una vez. Con la entrega como máximo una vez, el mensaje se entrega solo un máximo de una vez, pero no se garantiza que se entregue.
La variación final de las garantías de entrega es la entrega exactamente una vez. En este modelo, el sistema envía una sola copia del mensaje que se garantiza que se entregará.
Orden y duplicados
En las arquitecturas locales, los mensajes a menudo siguen un modelo FIFO. Para lograr este modelo, un sistema de procesamiento centralizado administra la secuencia de mensajes para garantizar un orden preciso. La mensajería ordenada crea desafíos porque, para cualquier mensaje con errores, todos los mensajes se deben volver a enviar en secuencia. Cualquier sistema centralizado puede convertirse en un desafío para la disponibilidad y la escalabilidad. Por lo general, solo se puede escalar un sistema central que administra el orden si se agregan más recursos a una máquina existente. Con un solo sistema que administra el orden, los problemas de confiabilidad afectan a todo el sistema y no solo a esa máquina.
Los servicios de mensajería altamente escalables y disponibles suelen usar varios sistemas de procesamiento para garantizar que los mensajes se entreguen al menos una vez. Con muchos sistemas, no se puede garantizar la administración del orden de los mensajes.
Las arquitecturas controladas por eventos no dependen del orden de los mensajes y pueden tolerar mensajes duplicados. Si se requiere un orden, los subsistemas pueden implementar técnicas de agregación y sistema de ventanas. Sin embargo, este enfoque sacrifica la escalabilidad y la disponibilidad en ese componente.
Técnicas de filtrado y fanout
Debido a que una transmisión de eventos puede contener datos que pueden o no ser necesarios para cada suscriptor, a menudo es necesario limitar los datos que recibe un suscriptor determinado. Existen dos patrones para administrar este requisito: filtros de eventos y fanouts de eventos.
En el siguiente diagrama, se muestra un sistema controlado por eventos con filtros de eventos que filtran los mensajes para suscriptores:
En el diagrama anterior, los filtros de eventos usan mecanismos de filtrado que limitan los eventos que llegan al suscriptor. En este modelo, un solo tema contiene todas las variaciones de un mensaje. En lugar de que un suscriptor lea cada mensaje y verifique si corresponde, la lógica de filtrado del sistema de mensajería evalúa el mensaje y no se lo entrega a los otros suscriptores.
En el siguiente diagrama, se muestra una variación del patrón de filtro de eventos llamado fanout de eventos que usa varios temas:
En el diagrama anterior, el tema principal contiene todas las variaciones de un mensaje, pero un mecanismo de distribución de eventos vuelve a publicar los mensajes en los temas relacionados con ese subconjunto de suscriptores.
Colas de mensajes no procesados
Incluso en los mejores sistemas, pueden producirse fallas. Las colas de mensajes no procesados son una técnica para abordar esas fallas. En la mayoría de las arquitecturas controladas por eventos, el sistema de mensajes continúa proporcionando un mensaje a un suscriptor hasta que el suscriptor lo confirma.
Si hay un problema con un mensaje, por ejemplo, caracteres no válidos en el cuerpo del mensaje, es posible que el suscriptor no pueda confirmar el mensaje. El sistema no puede manejar la situación o incluso puede finalizar el proceso.
Por lo general, los sistemas vuelven a intentar enviar los mensajes no confirmados o con errores. Si un mensaje no válido deja de confirmarse después de un período predeterminado, se agota el tiempo de espera del mensaje y, luego, se descarta del tema. Desde el punto de vista operativo, es útil revisar los mensajes, en lugar de que desaparezcan. Para lograrlo, se pueden usar las colas de mensajes sin procesar. En lugar de quitar el mensaje del tema, se mueve a otro tema en el que se puede volver a procesar o revisar para comprender por qué se generó el error.
Historial de transmisiones y repeticiones
Los flujos de eventos son flujos de datos continuos. El acceso a estos datos históricos es útil. Es posible que desees saber cómo un sistema logró un cierto estado. Es posible que tengas preguntas relacionadas con la seguridad que requieran una auditoría de los datos. Poder capturar un registro histórico de los eventos es fundamental en las operaciones a largo plazo de un sistema controlado por eventos.
Un uso común de los datos históricos de eventos es usarlos con un sistema de repetición. Las repeticiones se usan con fines de prueba. Mediante la repetición de datos de eventos de producción en otros entornos como el de pruebas y en etapa intermedia, puedes validar nuevas funciones en conjuntos de datos reales. También puedes reproducir datos históricos para recuperarte de un estado de error. Si un sistema falla o pierde datos, los equipos pueden volver a reproducir el historial de eventos desde un punto bueno conocido y el servicio puede reconstruir el estado que perdió.
Capturar estos eventos en colas basadas en registros o transmisiones de registros también es útil cuando los suscriptores necesitan acceso a una secuencia de eventos en diferentes momentos. Las transmisiones de registros se pueden ver en los sistemas con capacidades sin conexión. Si usas tu historial de transmisiones, puedes procesar las entradas nuevas más recientes mediante la lectura de la transmisión que comienza en el puntero última lectura.
Vistas de datos: tiempo real y casi en tiempo real
Con todos los datos que fluyen a través de los sistemas, es importante que puedas usar los datos. Existen muchas técnicas para acceder a estas transmisiones de eventos y usarlas, pero un caso práctico común es comprender el estado general de los datos en un momento específico. Estas suelen ser preguntas orientadas al cálculo, como “cuántos” o “nivel actual” que pueden usar otros sistemas o para consumo humano. Existen varias implementaciones que pueden responder estas preguntas:
- Un sistema en tiempo real puede ejecutarse de forma continua y realizar un seguimiento del estado actual. Sin embargo, como el sistema solo tiene un cálculo en la memoria, cualquier tiempo de inactividad establece el cálculo en cero.
- El sistema puede calcular valores de la tabla del historial para cada solicitud, pero esto puede convertirse en un problema porque tratar de calcular los valores de cada solicitud mientras los datos crecen pueden volverse inviable.
- El sistema puede crear instantáneas de los cálculos en intervalos específicos, pero el uso solo de instantáneas no refleja los datos en tiempo real.
Un patrón útil para implementar es una arquitectura de Lambda con capacidades casi en tiempo real y en tiempo real. Por ejemplo, una página de productos en un sitio de comercio electrónico puede usar vistas de datos de inventario casi en tiempo real. Cuando los clientes realizan pedidos, se usa un servicio en tiempo real para garantizar actualizaciones de estado hasta de segundos de los datos de inventario. Para implementar este patrón, el servicio responde a solicitudes casi en tiempo real de una tabla de instantáneas que contiene valores calculados en un intervalo determinado. Una solicitud en tiempo real usa la tabla de instantáneas y los valores de la tabla del historial desde la última instantánea para obtener el estado actual exacto. Estas vistas materializadas de los flujos de eventos proporcionan datos prácticos para impulsar procesos empresariales reales.
¿Qué sigue?
- Lee sobre Pub/Sub o Cloud Tasks para la integración asíncrona y el envío de mensajes.
- Prueba la guía de inicio rápido de Pub/Sub.
- Consulta la Descripción general de la arquitectura de Pub/Sub.
- Explora arquitecturas de referencia, diagramas y prácticas recomendadas sobre Google Cloud. Consulta nuestro Cloud Architecture Center.