He estado leyendo sobre el abastecimiento de eventos últimamente y realmente me gustan las ideas detrás de él, pero estoy atrapado con el siguiente problema.
Digamos que tiene N procesos concurrentes que reciben comandos (por ejemplo, servidores web), generan eventos como resultado y los almacenan en una tienda centralizada. Supongamos también que todo el estado de aplicación transitoria se mantiene en la memoria de los procesos individuales mediante la aplicación secuencial de eventos desde la tienda.
Ahora, supongamos que tenemos la siguiente regla comercial: cada usuario distinto debe tener un nombre de usuario único.
Si dos procesos reciben un comando de registro de usuario para el mismo nombre de usuario X, ambos verifican que X no está en su lista de nombres de usuario, la regla valida para ambos procesos y ambos almacenan un evento "nuevo usuario con nombre de usuario X" en la tienda .
Ahora hemos entrado en un estado global inconsistente porque se viola la regla de negocios (hay dos usuarios distintos con el mismo nombre de usuario).
En un sistema de estilo tradicional de servidor N <-> 1 RDBMS, la base de datos se usa como un punto central de sincronización que ayuda a prevenir tales inconsistencias.
Mi pregunta es: ¿cómo los sistemas de origen de eventos suelen abordar este problema? ¿Simplemente procesan cada comando secuencialmente (por ejemplo, limitan la cantidad de proceso que puede escribir en la tienda a 1)?
fuente
Respuestas:
En los sistemas de origen de eventos, la "tienda de eventos" cumple la misma función. Para un objeto de origen de evento, su escritura es un anexo de sus nuevos eventos a una versión particular de la secuencia de eventos. Entonces, al igual que con la programación concurrente, puede adquirir un bloqueo en ese historial al procesar el comando. Es más común que los sistemas de origen de eventos adopten un enfoque más optimista: cargue el historial anterior, calcule el nuevo historial y luego compare e intercambie. Si algún otro comando también ha escrito en esa secuencia, entonces su comparación e intercambio falla. A partir de ahí, puede volver a ejecutar su comando, o abandonar su comando, o tal vez incluso fusionar sus resultados en el historial.
La contención se convierte en un problema importante si todos los N servidores con sus comandos M intentan escribir en una sola secuencia. La respuesta habitual aquí es asignar un historial a cada entidad de origen de eventos en su modelo. Por lo tanto, el usuario (Bob) tendría un historial distinto del usuario (Alice), y las escrituras a una no bloquearán las escrituras a la otra.
Greg Young en Validación de set
¿Existe una manera elegante de verificar restricciones únicas en los atributos de los objetos de dominio sin mover la lógica empresarial a la capa de servicio?
La respuesta breve, en muchos casos, investigando ese requisito revela más profundamente que (a) es un proxy mal entendido para algún otro requisito, o (b) que las violaciones de la "regla" son aceptables si pueden detectarse (informe de excepción) , mitigados dentro de una ventana de tiempo, o son de baja frecuencia (por ejemplo: los clientes pueden verificar si hay un nombre disponible antes de enviar un comando para usarlo).
En algunos casos, cuando su tienda de eventos es buena para establecer la validación (es decir, una base de datos relacional), entonces implementa el requisito escribiendo en una tabla de "nombres únicos" en la misma transacción que persiste los eventos.
En algunos casos, solo puede hacer cumplir el requisito haciendo que todos los nombres de usuario se publiquen en la misma secuencia (que le permite evaluar el conjunto de nombres en la memoria, como parte de su modelo de dominio). - En este caso, dos procesos actualizarán el intento de actualizar "el" historial de flujo, pero una de las operaciones de comparar e intercambiar fallará, y el reintento de ese comando podrá detectar el conflicto.
fuente
Parece que podría implementar un proceso de negocio (
saga
en contexto deDomain Driven Design
) para el registro del usuario donde el usuario es tratado como unCRDT
.Recursos
https://doc.akka.io/docs/akka/current/distributed-data.html http://archive.is/t0QIx
"CRDT con datos distribuidos de Akka" https://www.slideshare.net/markusjura/crdts-with-akka-distributed-data para obtener más información
CmRDT
s - CRDT basados en operacionesCvRDT
s - CRTD basados en estadoEjemplos de código en Scala https://github.com/akka/akka-samples/tree/master/akka-sample-distributed-data-scala . Quizás el "carrito de compras" sea el más adecuado.
fuente