Usando Kafka como un almacén de eventos (CQRS). ¿Buena idea?

219

Aunque me he encontrado con Kafka antes, recientemente me di cuenta de que Kafka quizás podría usarse como (la base de) un CQRS , tienda de eventos .

Uno de los puntos principales que admite Kafka:

  • Captura / almacenamiento de eventos, todo HA, por supuesto.
  • Pub / sub arquitectura
  • Capacidad para reproducir el registro de eventos que permite a los nuevos suscriptores registrarse con el sistema después del hecho.

Es cierto que no estoy 100% versado en CQRS / fuente de eventos, pero esto parece bastante parecido a lo que debería ser un almacén de eventos. Lo curioso es que realmente no puedo encontrar tanto sobre el uso de Kafka como tienda de eventos, así que quizás me estoy perdiendo algo.

Entonces, ¿le falta algo a Kafka para que sea una buena tienda de eventos? ¿Funcionaría? ¿Usándolo en producción? Interesado en información, enlaces, etc.

Básicamente, el estado del sistema se guarda en función de las transacciones / eventos que el sistema ha recibido, en lugar de simplemente guardar el estado / instantánea actual del sistema, que es lo que generalmente se hace. (Piense en ello como un libro mayor en contabilidad: todas las transacciones finalmente se suman al estado final) Esto permite todo tipo de cosas interesantes, pero solo lea en los enlaces provistos.

Geert-Jan
fuente
Hola Geert-Jan En retrospectiva, ¿cómo lidiaste con este problema? Tengo una pregunta relacionada (expuesta aquí: stackoverflow.com/questions/58763727/… ). La mayoría de las personas que sugieren la adopción de Kafka parecen confiar en los puntos de inmutabilidad de apéndice-registro, alto rendimiento y garantía de orden de partición. Veo problemas relacionados con las búsquedas rápidas dentro de los temas (para la "reconstrucción" de la entidad), sin atomicidad transaccional y sin ordenar entre particiones. (100% garantía de pedido implica el uso de sólo el 1 partición -killing concurrencia)
tony _008
Al final no lo persuadí porque terminé ese proyecto paralelo. Así que no tengo una respuesta clara, me temo
Geert-Jan

Respuestas:

119

Kafka está destinado a ser un sistema de mensajería que tiene muchas similitudes con una tienda de eventos, sin embargo, para citar su introducción:

El clúster Kafka retiene todos los mensajes publicados, se hayan consumido o no, durante un período de tiempo configurable . Por ejemplo, si la retención se establece durante dos días, los dos días posteriores a la publicación de un mensaje estarán disponibles para el consumo, luego de lo cual se descartarán para liberar espacio. El rendimiento de Kafka es efectivamente constante con respecto al tamaño de los datos, por lo que retener muchos datos no es un problema.

Entonces, si bien los mensajes pueden retenerse indefinidamente, la expectativa es que se eliminarán. Esto no significa que no pueda usar esto como una tienda de eventos, pero puede ser mejor usar otra cosa. Echa un vistazo a EventStore para una alternativa.

ACTUALIZAR

Documentación de Kafka :

El abastecimiento de eventos es un estilo de diseño de aplicaciones donde los cambios de estado se registran como una secuencia de registros ordenada por tiempo. El soporte de Kafka para datos de registro almacenados muy grandes lo convierte en un excelente back-end para una aplicación construida en este estilo.

ACTUALIZACIÓN 2

Una preocupación con el uso de Kafka para el abastecimiento de eventos es la cantidad de temas requeridos. Por lo general, en el abastecimiento de eventos, hay una secuencia (tema) de eventos por entidad (como usuario, producto, etc.). De esta manera, el estado actual de una entidad se puede reconstituir volviendo a aplicar todos los eventos en la secuencia. Cada tema de Kafka consta de una o más particiones y cada partición se almacena como un directorio en el sistema de archivos. También habrá presión de ZooKeeper a medida que aumente el número de znodes.

eulerfx
fuente
16
Estaba mirando a Kafka y tenía otra preocupación: no noté nada sobre la concurrencia optimista. Idealmente podría decir: "Agregue este evento como elemento N + 1 solo si el evento más reciente del objeto sigue siendo N."
Darien
2
@Darien: Probablemente voy con una configuración en la que Redis alimenta a Kafka (usando las notificaciones de Redis ). Dado que Redis permite una concurrencia optimista (usando Watch / multi-exec), esto debería funcionar
Geert-Jan
2
@Darien No soy un experto en el abastecimiento de eventos, pero entendí que, en general, no necesitarías una concurrencia optimista porque los eventos son, por definición, registros de cosas que ya han sucedido históricamente.
John
44
@John Creo que si ya tiene un orden autorizado de eventos no conflictivos, eso implica que donde sea que vivan es su tecnología de tienda de eventos real, y Kafka solo se está utilizando como un sistema secundario para distribuirlos.
Darien
1
También hay información valiosa aquí: groups.google.com/forum/#!topic/dddcqrs/rm02iCfffUY
manuc66
283

Soy uno de los autores originales de Kafka. Kafka funcionará muy bien como un registro para el abastecimiento de eventos. Es tolerante a fallas, escala a enormes tamaños de datos y tiene un modelo de particionamiento incorporado.

Lo usamos para varios casos de uso de este formulario en LinkedIn. Por ejemplo, nuestro sistema de procesamiento de flujo de código abierto, Apache Samza, viene con soporte incorporado para el abastecimiento de eventos.

Creo que no escuchas mucho sobre el uso de Kafka para el abastecimiento de eventos principalmente porque la terminología del abastecimiento de eventos no parece ser muy frecuente en el espacio web del consumidor donde Kafka es más popular.

He escrito un poco sobre este estilo de uso de Kafka aquí .

Jay Kreps
fuente
2
Iba a publicar ese enlace :) Impresionante publicación de blog. Hubiera sido bueno poder comentarlo porque tengo muchas preguntas. @ Geert-Jan también echó un vistazo a la "arquitectura Lambda", esto es bastante similar y el nombre es dado por el autor de Storm, utilizando principalmente algún tipo de registro de eventos basado en hadoop en muchos ejemplos
Sebastien Lorber
66
@ Jay: Dado que he renovado el interés en este tema, ¿podría explicar un poco el hecho de que Kafka parece estar diseñada para que sus mensajes publicados expiren después de un período de tiempo establecido? Si usa Kafka como fuente de eventos, los mensajes deben almacenarse indefinidamente. Probablemente sea configurable, pero ¿plantearía esto un problema?
Geert-Jan
2
¿Hay alguna comparación entre kafka y tienda de eventos? Específicamente, me gusta el enfoque en FRP en el almacén de eventos llamado Proyecciones. ¿Hay algo así en Kafka / Samza?
CMCDragonkai
44
También estoy interesado en la pregunta de @ Geert-Jan a Jay. Kafka no es adecuado para el lado transaccional del origen de eventos real, debido a la necesidad de una secuencia de eventos (tema) por agregado de dominio (piense en millones). Sin embargo, es ideal para recibir eventos desde, por ejemplo, GetEventStore. Pero esto solo funcionará con eventos infinitamente retenidos (en nuestro caso), y aparte de algunos breves comentarios, ¿este no parece ser un caso de uso compatible de Kafka? ¿Me equivoco aquí? Samza, por ejemplo, supone que solo hay dos escenarios: retención basada en tiempo o retención basada en clave. Hay otros ..
Stephen Drew
3
@eulerfx Suponiendo que nos gustaría usar Kafka como almacenamiento para el sistema de origen de eventos, ¿cómo debería implementarse el bloqueo / concurrencia optimista?
Krzysztof Branicki
51

Sigo volviendo a este control de calidad. Y no encontré las respuestas existentes lo suficientemente matizadas, así que estoy agregando esta.

TL; DR. Sí o No, dependiendo del uso de su fuente de eventos.

Hay dos tipos principales de sistemas de origen de eventos que conozco.

Procesadores de eventos posteriores = Sí

En este tipo de sistema, los eventos ocurren en el mundo real y se registran como hechos. Tal como un sistema de almacén para realizar un seguimiento de las paletas de productos. Básicamente no hay eventos en conflicto. Todo ya ha sucedido, incluso si estuvo mal. (Es decir, el pallet 123456 se colocó en el camión A, pero estaba programado para el camión B.) Luego, se verifican las excepciones a través de mecanismos de informes. Kafka parece adecuado para este tipo de aplicación de procesamiento de eventos descendente.

En este contexto, es comprensible por qué la gente de Kafka lo defiende como una solución de Abastecimiento de eventos. Porque es bastante similar a cómo ya se usa, por ejemplo, en secuencias de clics. Sin embargo, las personas que usan el término Abastecimiento de eventos (a diferencia del procesamiento de flujo) probablemente se refieran al segundo uso ...

Fuente de verdad controlada por la aplicación = No

Este tipo de aplicación declara sus propios eventos como resultado de las solicitudes de los usuarios que pasan por la lógica empresarial. Kafka no funciona bien en este caso por dos razones principales.

Falta de aislamiento de la entidad.

Este escenario necesita la capacidad de cargar la secuencia de eventos para una entidad específica. La razón común para esto es construir un modelo de escritura transitoria para que la lógica de negocios utilice para procesar la solicitud. Hacer esto no es práctico en Kafka. El uso de tema por entidad podría permitir esto, excepto que esto no es un comienzo cuando puede haber miles o millones de entidades. Esto se debe a límites técnicos en Kafka / Zookeeper.

Una de las principales razones para utilizar un modelo de escritura transitoria de esta manera es hacer que los cambios en la lógica de negocios sean baratos y fáciles de implementar.

En su lugar, se recomienda el uso de tema por tipo para Kafka, pero esto requeriría cargar eventos para cada entidad de ese tipo solo para obtener eventos para una sola entidad. Como no puede determinar por posición de registro qué eventos pertenecen a qué entidad. Incluso usando Instantáneas para comenzar desde una posición de registro conocida, este podría ser un número significativo de eventos para pasar.

Falta de detección de conflictos

En segundo lugar, los usuarios pueden crear condiciones de carrera debido a solicitudes concurrentes contra la misma entidad. Puede ser bastante indeseable guardar eventos en conflicto y resolverlos después del hecho. Por lo tanto, es importante poder prevenir eventos conflictivos. Para escalar la carga de solicitudes, es común usar servicios sin estado mientras se evitan conflictos de escritura usando escrituras condicionales (solo escriba si el último evento de entidad fue #x). Aka concurrencia optimista. Kafka no admite simultaneidad optimista. Incluso si lo apoyara a nivel de tema, tendría que estar todo el camino hasta el nivel de entidad para ser efectivo. Para usar Kafka y evitar eventos conflictivos, necesitaría usar un escritor con estado y serializado a nivel de aplicación. Este es un requisito / restricción arquitectónica importante.

Más información


Actualización por comentario

El comentario se ha eliminado, pero la pregunta era algo así como: ¿qué utilizan las personas para el almacenamiento de eventos?

Parece que la mayoría de las personas implementa su propia implementación de almacenamiento de eventos sobre una base de datos existente. Para escenarios no distribuidos, como productos internos o productos independientes, está bien documentado cómo crear un almacén de eventos basado en SQL. Y hay bibliotecas disponibles sobre una base de datos de varios tipos. También está EventStore , que está diseñado para este propósito.

En escenarios distribuidos, he visto un par de implementaciones diferentes. El proyecto Jet's Panther usa Azure CosmosDB , con la función Cambiar fuente para notificar a los oyentes. Otra implementación similar de la que he oído hablar en AWS es usar DynamoDB con su función Streams para notificar a los oyentes. La clave de partición probablemente debería ser la identificación del flujo para la mejor distribución de datos (para disminuir la cantidad de sobreaprovisionamiento). Sin embargo, una reproducción completa a través de transmisiones en Dynamo es costosa (lectura y costo). Por lo tanto, este impl también se configuró para Dynamo Streams para volcar eventos en S3. Cuando un nuevo oyente se conecta, o un oyente existente quiere una repetición completa, leería S3 para ponerse al día primero.

Mi proyecto actual es un escenario multiinquilino, y rodé el mío sobre Postgres. Algo parecido a Citus parece apropiado para la escalabilidad, partición por tentant + stream.

Kafka sigue siendo muy útil en escenarios distribuidos. Es un problema no trivial exponer los eventos de cada servicio a otros servicios. Por lo general, no se crea una tienda de eventos para eso, pero eso es precisamente lo que Kafka hace bien. Cada servicio tiene su propia fuente interna de verdad (podría ser el almacenamiento de eventos o no), pero escucha a Kafka para saber qué está sucediendo "afuera". El servicio también puede publicar eventos en Kafka para informar al "exterior" de cosas interesantes que hizo el servicio.

Kasey Speakman
fuente
1
@Dominik Mencioné EventStore en la sección Actualización (segundo párrafo). Volveré y lo vincularé. Lo he intentado y tiene un rendimiento impresionante. Para nuestro pequeño equipo, no introducir otra base de datos se consideró más importante por el momento, por lo tanto, Postgres (que también se usa para las vistas). Es posible que nos traslademos a EventStore en el futuro o en futuros productos.
Kasey Speakman
2
@KaseySpeakman Los temas no son lo mismo que las particiones. Un tema tiene una o más particiones. Se garantiza que las particiones solo tendrán un consumidor por grupo en un momento dado. Particione sus entidades de tal manera que aproveche eso. No necesita un tema por entidad o incluso una partición por entidad. Simplemente necesita particionarlos de tal manera que garantice que todos los comandos dirigidos a la misma entidad vayan a la misma partición.
Andrew Larsson
1
@KaseySpeakman Muchas entidades pueden compartir una sola partición. ¿Quién dijo que siempre debe cargar el estado de la entidad directamente desde la tienda de eventos al reproducir los eventos? Hay otras formas de lograr el mismo concepto sin seguir estrictamente la implementación línea por línea de Greg Young.
Andrew Larsson,
1
@AndrewLarsson Si no particiona por entidad, ¿cómo va a evitar eventos conflictivos a nivel de entidad? Dado que hemos cerrado el círculo de vuelta a los conflictos de concurrencia, entonces quizás debería publicar su propio artículo en medio o algo sobre cómo ha utilizado Kafka para el abastecimiento de eventos (no el procesamiento continuo) en la producción. Cómo se logra con la partición por tipo y sin control de concurrencia a nivel de entidad. Lo leería, y ni siquiera te molestaría en comentarios si no estuviera de acuerdo.
Kasey Speakman
2
@KaseySpeakman Usar Kafka de esta manera no es fácil de ninguna manera. Pero si está en la escala en la que consideró seriamente CQRS y Event Sourcing, entonces está en la escala donde no puede permitirse hacer las cosas de la manera fácil. Su modelo de concurrencia tiene un impacto directo en su escala; no elija uno arbitrariamente. Además, HTTP no es un transporte confiable y, de nuevo, si está a esa escala, no puede permitirse el lujo de perder tiempo resolviendo problemas de mensajes perdidos o duplicados. Todo esto se puede resolver usando Kafka entre el cliente y el procesador de comandos, pero sí, tiene un costo de complejidad.
Andrew Larsson el
20

Puede usar Kafka como tienda de eventos, pero no recomiendo hacerlo, aunque podría parecer una buena opción:

  • Kafka solo garantiza al menos una vez la entrega y hay duplicados en la tienda de eventos que no se pueden eliminar. Actualización: Aquí puede leer por qué es tan difícil con Kafka y algunas últimas noticias sobre cómo finalmente lograr este comportamiento: https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how -apache-kafka-does-it /
  • Debido a la inmutabilidad, no hay forma de manipular el almacén de eventos cuando la aplicación evoluciona y los eventos deben transformarse (por supuesto, hay métodos como la transmisión, pero ...). Una vez podría decir que nunca necesita transformar eventos, pero eso no es una suposición correcta, podría haber una situación en la que haga una copia de seguridad del original, pero los actualice a las últimas versiones. Ese es un requisito válido en arquitecturas controladas por eventos.
  • No hay lugar para persistir las instantáneas de entidades / agregados y la reproducción será cada vez más lenta. La creación de instantáneas debe presentarse para la tienda de eventos desde una perspectiva a largo plazo.
  • Dado que las particiones Kafka se distribuyen y son difíciles de administrar y hacer copias de seguridad en comparación con las bases de datos. Las bases de datos son simplemente más simples :-)

Entonces, antes de hacer su elección, lo piensa dos veces. La tienda de eventos como combinación de interfaces de capa de aplicación (monitoreo y administración), la tienda SQL / NoSQL y Kafka como agente es la mejor opción que dejar que Kafka maneje ambas funciones para crear una solución completa de funciones completas.

La tienda de eventos es un servicio complejo que requiere más de lo que Kafka puede ofrecer si se toma en serio la aplicación de fuentes de eventos, CQRS, Sagas y otros patrones en la arquitectura impulsada por eventos y mantiene un alto rendimiento.

¡Siéntete libre de desafiar mi respuesta! Es posible que no le guste lo que digo sobre su corredor favorito con muchas capacidades superpuestas, pero aún así, Kafka no fue diseñado como tienda de eventos, sino más bien como corredor de alto rendimiento y amortiguador al mismo tiempo para manejar escenarios de productores rápidos versus consumidores lentos, por ejemplo.

Consulte el marco de código abierto de microservicios eventuate.io para descubrir más sobre los posibles problemas: http://eventuate.io/

Actualización a partir del 8 de febrero de 2018

No incorporo nueva información de los comentarios, pero estoy de acuerdo con algunos de esos aspectos. Esta actualización trata más sobre algunas recomendaciones para la plataforma basada en eventos de microservicios. Si se toma en serio el diseño robusto de microservicios y el mayor rendimiento posible en general, le proporcionaré algunas sugerencias que podrían interesarle.

  1. No use Spring, es genial (lo uso mucho), pero es pesado y lento al mismo tiempo. Y no es una plataforma de microservicio en absoluto. Es "solo" un marco para ayudarlo a implementar uno (mucho trabajo detrás de esto ...). Otros marcos son "simplemente" REST o JPA livianos o marcos enfocados de manera diferente. Recomiendo probablemente la mejor plataforma de microservicio de código abierto disponible en su clase que vuelve a las raíces puras de Java: https://github.com/networknt

Si se pregunta sobre el rendimiento, puede compararse con el conjunto de pruebas de referencia existente. https://github.com/networknt/microservices-framework-benchmark

  1. No uses Kafka en absoluto :-)) Es una broma a medias. Quiero decir que si bien Kafka es genial, es otro sistema centrado en corredores. Creo que el futuro está en los sistemas de mensajería sin intermediario. Puede que se sorprenda, pero hay sistemas más rápidos que Kafka :-), por supuesto, debe bajar al nivel inferior. Mira la crónica.

  2. Para la tienda de eventos, recomiendo la extensión superior Postgresql llamada TimescaleDB, que se centra en el procesamiento de datos de series de tiempo de alto rendimiento (los eventos son series de tiempo) en gran volumen. Por supuesto, CQRS, el abastecimiento de eventos (funciones de repetición, etc.) se integran en light4j framework fuera de la caja que usa Postgres como poco almacenamiento.

  3. Para la mensajería intente mirar Chronicle Queue, Map, Engine, Network. Me refiero a deshacerse de estas antiguas soluciones centradas en corredores e ir con el sistema de micro mensajería (integrado). Chronicle Queue es incluso más rápido que Kafka. Pero estoy de acuerdo en que no es una solución todo en uno y que necesita hacer un desarrollo, de lo contrario, vaya y compre la versión Enterprise (de pago). Al final, el esfuerzo de construir desde Chronicle su propia capa de mensajería se pagará eliminando la carga de mantener el clúster de Kafka.

kensai
fuente
Interesante vista. ¿Te importaría elaborar algunos puntos? > Kafka solo garantiza al menos una vez la entrega y hay duplicados en la tienda de eventos que no se pueden eliminar. Parece implicar que existe tal cosa como exactamente una vez la entrega. afaik (y estoy bastante seguro de eso) no existe tal cosa en un sistema distribuido. 2) En cuanto a su punto 2: la escuela clásica de pensamiento (abastecimiento de eventos / dddd) es que los eventos son inherentemente inmutables. Es decir: sucedieron, no hay forma de cambiar el pasado. ¿Cuál es el caso de uso real de cambiarlos en retrospectiva? ¡Gracias!
Geert-Jan
1.) Hazelcast para garantizar que cada mensaje se procesará una vez y solo una vez. 2.) No me gusta nada como _V2 en el código de servicio, por lo que puede hacer una copia de seguridad para archivar y recrear eventos antiguos en sus nuevas versiones (todavía tiene la verdad original), o puede ocultar / construir esta funcionalidad directamente en Evento Funcionalidad de instantánea de la tienda, por lo que hay un único punto de transmisión -> la tienda de eventos. ¿Cuáles son sus soluciones para esto?
kensai
1) al menos una vez + idempotencia en el consumidor. Es decir: compruebe si el evento ya se ha visto. Si es así, salta. O mejor aún, tener acciones idempotentes. Por supuesto, esto no siempre es posible. 2) Nunca me he encontrado con la necesidad de versionar eventos. Siempre trato los eventos en sí mismos como la fuente de la verdad e incluyo toda la información que pueda necesitar sobre ellos. Al hacer esto, nunca me he encontrado con una situación en la que necesite una estructura de evento diferente o datos sobre un evento. Pero tal vez ymmv. Interesado en saber en qué situaciones necesitaría tener eventos actualizados.
Geert-Jan
1.) puede ser una opción ... 2.) entonces sus estructuras de datos fueron perfectas desde el principio :-) suerte, jaja. Puede que no lo necesite en mi proyecto actual, pero estoy construyendo una plataforma completa en horquillas de eventuate.io fusionada con algunos enfoques JEE de alto rendimiento tomados del eventuate ligero 4j ... toda esta discusión no es lugar para comentarios sobre stackoverflow , pero si está interesado en profundizar, le recomiendo este artículo: leanpub.com/esversioning/read
kensai
1
Kafka admite exactamente una vez la entrega ahora, por cierto. Actualizar viñeta 1
OneCricketeer
8

Sí, puedes usar Kafka como tienda de eventos. Funciona bastante bien, especialmente con la introducción de Kafka Streams , que proporciona una forma nativa de Kafka para procesar sus eventos en un estado acumulado que puede consultar .

Respecto a:

Capacidad para reproducir el registro de eventos que permite a los nuevos suscriptores registrarse con el sistema después del hecho.

Esto puede ser complicado. Cubrí eso en detalle aquí: https://stackoverflow.com/a/48482974/741970

Dmitry Minkovsky
fuente
0

Sí, Kafka funciona bien en el modelo de aprovisionamiento de eventos especialmente CQRS, sin embargo, debe tener cuidado al configurar TTL para los temas y siempre tenga en cuenta que Kafka no fue diseñado para este modelo, sin embargo, podemos usarlo muy bien.

Brijendra Verma
fuente
0

Creo que deberías mirar axon framework junto con su soporte para Kafka

Darshu Bc
fuente