Una arquitectura basada en eventos consta de productores de eventos que generan un flujo de eventos, y consumidores de eventos que escuchan los eventos.
Los eventos se entregan casi en tiempo real, de modo que los consumidores pueden responder inmediatamente a los eventos cuando se producen. Los productores se desacoplan de los consumidores. Un productor no sabe qué consumidores están escuchando. Los consumidores también se desconectan entre sí, y cada consumidor ve todos los eventos. Esto difiere de un patrón Competing Consumers, donde los consumidores extraen los mensajes de una cola y los mensajes solo se procesan una vez (suponiendo que no haya errores). En algunos sistemas, como IoT, los eventos se deben ingerir en volúmenes muy altos.
Una arquitectura basada en eventos puede usar un modelo publicar/subscribir (también llamado pub/sub) o un modelo de flujo de eventos.
Pub/sub: la infraestructura de mensajería mantiene el seguimiento de las suscripciones. Cuando se publica un evento, se envía el evento a cada suscriptor. Después de que se recibe un evento, no se puede reproducir, y los nuevos suscriptores no ven el evento.
Streaming de eventos: los eventos se escriben en un registro. Los eventos siguen un orden estricto (dentro de una partición) y son duraderos. Los clientes no se suscriben al flujo, sino que un cliente puede leer desde cualquiera de sus partes. El cliente es responsable de avanzar su posición en el flujo. Esto significa que un cliente puede unirse en cualquier momento y puede reproducir los eventos.
En el lado del consumidor, hay algunas variaciones comunes:
Procesamiento sencillo de eventos. Un evento desencadena inmediatamente una acción en el consumidor. Por ejemplo, podría usar Azure Functions con un desencadenador de Service Bus para que una función se ejecute cada vez que se publica un mensaje en un tema de Service Bus.
correlación de eventos básica. Un consumidor requiere procesar un pequeño número de eventos comerciales discretos, normalmente correlacionados por algún identificador, conservando cierta información de eventos anteriores para utilizarla al procesar eventos posteriores. Este patrón es compatible con bibliotecas como NServiceBus y MassTransit.
Procesamiento de eventos complejos. Un consumidor procesa una serie de eventos, en busca de patrones en los datos de eventos, mediante una tecnología como Azure Stream Analytics. Por ejemplo, podría agregar las lecturas de un dispositivo insertado durante una ventana de tiempo y generar una notificación si la media móvil supera un umbral determinado.
Procesamiento de flujo de eventos. Use una plataforma de flujo de datos, como Azure IoT Hub o Apache Kafka, como canalización para ingerir eventos y suministrarlos a procesadores de flujo. Los procesadores de flujos sirven para procesar o transformar el flujo. Puede haber varios procesadores de flujo para diferentes subsistemas de la aplicación. Este enfoque es una buena opción para las cargas de trabajo de IoT.
El origen de los eventos puede ser externo con respecto al sistema, como dispositivos físicos en una solución de IoT. En ese caso, el sistema debe ser capaz de ingerir los datos según el volumen y el rendimiento que requiere el origen de datos.
En el diagrama lógico anterior, se muestra cada tipo de consumidor como un solo cuadro. En la práctica, es habitual tener varias instancias de un consumidor para evitar hacer que el consumidor se convierta en un único punto de error en el sistema. También podrían ser necesarias varias instancias para administrar el volumen y la frecuencia de los eventos. Además, un único consumidor podría procesar eventos en varios subprocesos. Esto puede crear dificultades si los eventos se deben procesar en orden o requieren la semántica de tipo "exactly-once". Consulte Minimizar la coordinación.
Hay dos topologías principales en muchas arquitecturas controladas por eventos:
Topología de agente. Los componentes difunden repeticiones como eventos en todo el sistema y otros componentes actúan sobre el evento o simplemente omiten el evento. Esta topología es útil cuando el flujo de procesamiento de eventos es relativamente sencillo. No hay coordinación central ni orquestación, por lo que esta topología puede ser muy dinámica. Esta topología está muy desacoplada, lo que ayuda a proporcionar escalabilidad, capacidad de respuesta y tolerancia a errores de componentes. Ningún componente posee o conoce el estado de ninguna transacción empresarial de varios pasos y las acciones se realizan de forma asincrónica. Posteriormente, las transacciones distribuidas son arriesgadas porque no hay ningún medio nativo para reiniciarse o reproducirse. Es necesario tener muy en cuenta el control de errores y las estrategias de intervención manual, ya que esta topología puede ser un origen de incoherencia de datos.
Topología de mediador. Esta topología aborda algunas de las deficiencias de la topología de agente. Hay un mediador de eventos que administra y controla el flujo de eventos. El mediador de eventos mantiene el estado y administra las funcionalidades de control y reinicio de errores. A diferencia de la topología de agente, los componentes difunden repeticiones como comandos y solo a canales designados, normalmente colas de mensajes. No se espera que sus consumidores omitan estos comandos. Esta topología ofrece un mayor control, un control de errores distribuidos mejor distribuido y una mayor coherencia de los datos. Esta topología introduce un mayor acoplamiento entre componentes y el mediador de eventos podría convertirse en un cuello de botella o un problema de fiabilidad.
Cuándo utilizar esta arquitectura
- Varios subsistemas deben procesar los mismos eventos.
- Procesamiento en tiempo real con retardo mínimo.
- Procesamiento de eventos complejos, como coincidencia de patrones o agregación durante ventanas de tiempo.
- Gran volumen y alta velocidad de datos, como IoT.
Ventajas
- Se desvinculan productores y consumidores.
- No existen integraciones de punto a punto. Es fácil agregar nuevos consumidores al sistema.
- Los consumidores pueden responder a eventos inmediatamente a medida que llegan.
- Muy escalable y distribuida.
- Los subsistemas tienen vistas independientes del flujo de eventos.
Desafíos
Entrega garantizada.
En algunos sistemas, especialmente en escenarios de IoT, es fundamental garantizar la entrega de los eventos.
Procesamiento de eventos en orden o exactamente una vez.
Cada tipo de consumidor normalmente se ejecuta en varias instancias, a fin de conseguir resistencia y escalabilidad. Esto puede suponer un desafío si se deben procesar los eventos en orden (dentro de un tipo de consumidor), o si la lógica de procesamiento de mensaje idempotente no es idempotente.
Coordinación de mensajes entre servicios.
Los procesos empresariales suelen implicar la publicación y suscripción de varios servicios a los mensajes para lograr un resultado coherente en toda una carga de trabajo. Los patrones de flujo de trabajo como el patrón de coreografía y Saga Orchestration se pueden usar para administrar de forma confiable los flujos de mensajes en varios servicios.
Control de errores.
La arquitectura controlada por eventos usa principalmente comunicación asincrónica. Un desafío con la comunicación asincrónica es el control de errores. Una manera de solucionar este problema es usar un procesador de controlador de errores independiente. Así, cuando el consumidor de eventos experimenta un error, envía inmediatamente y de forma asíncrona el evento erróneo al procesador del controlador de errores y sigue adelante. El procesador del controlador de errores intenta corregir el error y devuelve el evento al canal de ingesta original. Pero si se produce un error en el procesador del controlador de errores, puede enviar el evento erróneo a un administrador para su posterior inspección. Si usa un procesador de controladores de errores, los eventos erróneos se procesarán fuera de secuencia cuando se vuelvan a enviar.
Pérdida de datos.
Otro desafío con la comunicación asincrónica es la pérdida de datos. Si alguno de los componentes se bloquea antes de procesar y entregar correctamente el evento a su siguiente componente, el evento se quita y nunca lo convierte en el destino final. Para minimizar la posibilidad de pérdida de datos, conserve los eventos en tránsito y quite o quite los eventos solo cuando el siguiente componente haya confirmado la recepción del evento. Estas características se conocen normalmente como modo de confirmación de cliente y soporte técnico del último participante.
Implementación de un patrón tradicional de solicitud-respuesta.
A veces, el productor de eventos requiere una respuesta inmediata del consumidor de eventos, como obtener una elegibilidad del cliente antes de continuar con un pedido. En la arquitectura controlada por eventos, la comunicación sincrónica se puede lograr a través de la mensajería de solicitud-respuesta.
Normalmente, este patrón se implementa mediante el uso de varias colas: una cola de solicitudes y una cola de respuesta. El productor de eventos envía una solicitud asincrónica a una cola de solicitudes, pausa otra operación en esa tarea y espera una respuesta en la cola de respuestas; convertir esto de forma eficaz en un proceso sincrónico. A continuación, los consumidores de eventos procesan la solicitud y envían la respuesta a través de una cola de respuesta. Este enfoque suele usar un identificador de sesión para el seguimiento, por lo que el productor de eventos sabe qué mensaje de la cola de respuesta está relacionado con la solicitud específica. La solicitud original también podría especificar el nombre de la cola de respuesta, potencialmente efímera, en un encabezado de respuesta u otro atributo personalizado acordado mutuamente.
Consideraciones adicionales
- La cantidad de datos que se va a incluir en un evento puede ser una consideración importante que afecta al rendimiento y los costos. Incluir toda la información relevante que se necesita para el procesamiento en el propio evento permite simplificar el código de procesamiento y ahorrar búsquedas adicionales. Si se incluye una cantidad mínima de información en un evento (por ejemplo, solo un par de identificadores), el tiempo de transporte y el costo se reducirán, pero será necesario que el código de procesamiento busque cualquier información adicional que necesite. Para más información, eche un vistazo a esta entrada de blog.
- Aunque una solicitud solo es visible para el componente que controla solicitudes, los eventos a menudo son visibles para varios componentes de una carga de trabajo, incluso si dichos componentes no los consumen o no están destinados a hacerlo. Si se opera con una mentalidad de "asunción de que hay brechas", hay que tener cuidado con la información que se incluye en los eventos para evitar la exposición involuntaria de información.
- Muchas aplicaciones usan la arquitectura controlada por eventos como su arquitectura principal; sin embargo, este enfoque se puede combinar con otros estilos arquitectónicos, lo que da lugar a arquitecturas híbridas. Entre las combinaciones comunes se incluyen microservicios y canalizaciones y filtros. La integración de la arquitectura controlada por eventos mejora el rendimiento del sistema al eliminar cuellos de botella y proporcionar presión de retroceso durante grandes volúmenes de solicitudes.
Recursos relacionados
- Vídeo de discusión de la Comunidad sobre las consideraciones de elección entre coreografía y orquestación.