Microservicios: cómo manejar las relaciones de clave externa

85

La arquitectura de microservicios sugiere que cada servicio debe manejar sus propios datos. Por lo tanto, cualquier servicio (Servicio A) que dependa de los datos que pertenecen a otro servicio (servicio B) debe acceder a dichos datos no haciendo llamadas directas a DB sino a través de la API proporcionada por el segundo servicio (servicio B).

Entonces, ¿qué sugieren las mejores prácticas de microservicios para verificar las restricciones de claves externas?

Ejemplo: estoy desarrollando una función de entrega (microservicio 1) para productos y ciertos productos se pueden entregar solo en ciertas ubicaciones, como se menciona en la tabla de productos, accesible solo para productos microservicio (mircoservice 2).

¿Cómo me aseguro de que el microservicio 1 (es decir, la función de entrega) no lleve un pedido a una ubicación sin servicio? Tengo esta pregunta porque la función de entrega no puede acceder directamente a la base de datos de productos, por lo que no hay restricciones aplicables a nivel de base de datos cuando se coloca una orden de entrega en la base de datos de entrega (no es posible verificar si existe una coincidencia de clave externa en la base de datos de productos o mesa).


fuente

Respuestas:

71

Es posible utilizar una base de datos compartida para varios microservicios. Puede encontrar los patrones para la gestión de datos de microservicios en este enlace: http://microservices.io/patterns/data/database-per-service.html . Por cierto, es un blog muy útil para la arquitectura de microservicios.

En su caso, prefiere utilizar la base de datos por patrón de servicio. Esto hace que los microservicios sean más autónomos. En esta situación, debe duplicar algunos de sus datos entre varios microservicios. Puede compartir los datos con llamadas a API entre microservicios o puede compartirlos con mensajería asincrónica. Depende de su infraestructura y la frecuencia de cambio de los datos. Si no cambia con frecuencia, debe duplicar los datos con eventos asíncronos.

En su ejemplo, el servicio de entrega puede duplicar las ubicaciones de entrega y la información del producto. El servicio de productos gestiona los productos y las ubicaciones. Luego, los datos requeridos se copian en la base de datos del servicio de entrega con mensajes asíncronos (por ejemplo, puede usar rabbit mq o apache kafka). El servicio de entrega no cambia los datos del producto y la ubicación, pero usa los datos cuando está haciendo su trabajo. Si la parte de los datos del producto que utiliza el servicio de entrega cambia con frecuencia, la duplicación de datos con mensajería asíncrona será muy costosa. En este caso, debe realizar llamadas api entre el producto y el servicio de entrega. El servicio de entrega solicita al servicio de productos que verifique si un producto se puede entregar en una ubicación específica o no. El servicio de entrega solicita el servicio de Productos con un identificador (nombre, identificación, etc.) de un producto y ubicación. Estos identificadores se pueden tomar del usuario final o se comparten entre microservicios. Debido a que las bases de datos de los microservicios son diferentes aquí, no podemos definir claves externas entre los datos de estos microservicios.

Las llamadas de API pueden ser más fáciles de implementar, pero el costo de la red es mayor en esta opción. Además, sus servicios son menos autónomos cuando realiza llamadas a la API. Porque, en su ejemplo, cuando el servicio del producto está inactivo, el servicio de entrega no puede hacer su trabajo. Si duplica los datos con mensajería asincrónica, los datos necesarios para realizar la entrega se encuentran en la base de datos del microservicio de entrega. Cuando el servicio del Producto no esté funcionando, podrá realizar la entrega.

Ali Sağlam
fuente
2
Gran respuesta. Utilizo llamadas a API, pero también necesita ordenar y paginar los datos de otro servicio. ¿Conoce el mejor enfoque para ese caso?
tranceholic
6
Debe agregar los parámetros relacionados con la paginación y la ordenación a su api. Entonces, la responsabilidad de obtener la página correcta con el orden correcto será asumida por los consumidores de la API. Hay algunas tecnologías que se utilizan para definir una API como GraphQL. Hasta donde yo sé, esas tecnologías ya tienen funciones de clasificación y paginación. Si no está utilizando este tipo de tecnología, simplemente puede obtener los parámetros de su cliente y usarlos para devolver sus datos ordenados por páginas.
Ali Sağlam
1
¡Gran respuesta de hecho!
TS
2
Pero, ¿conservas la clave externa? Ej: cada publicación de blog tendrá muchos comentarios. Monolith tendrá una tabla de comentarios con clave externa a la publicación del blog. Sin embargo en microservicio tendremos dos servicios. Servicio 1: Post Microservie con estos campos de tabla (PostID, Nombre, Contenido) Servicio 2: Comentarios Microservie con estos campos de tabla (CommentID, PostID, Cpmment) La pregunta es, ¿Necesitamos "PostID" en el servicio 2 (Comentarios Microservicio)? Supongo que la respuesta es sí, ya que necesitamos saber qué comentario pertenece a qué publicación. ¿Mi comprensión es correcta?
rakesh mehra
1
Cómo dividir un sistema en microservicios es una historia totalmente diferente, pero si decidió crear 2 microservicios, como publicación y comentario, necesita un identificador de publicación en el microservicio de comentarios, ya que cada comentario pertenece a una publicación. Sin embargo, no significa que deba definir FK entre esas tablas. FK es solo una restricción en el mundo RDBMS que ayuda a garantizar la integridad y consistencia de los datos. Si mantiene los datos de estos microservicios en esquemas separados, no puede definir FK o incluso puede mantener los datos de uno en una base de datos nosql (lo que tendría sentido para el microservicio de comentarios) donde FK no es aplicable.
Ali Sağlam
24

Al distribuir su código para lograr un acoplamiento reducido, desea evitar compartir recursos y los datos son un recurso que desea evitar compartir.

Otro punto es que solo un componente en su sistema posee los datos (para operaciones de cambio de estado), otros componentes pueden LEER pero NO ESCRIBIR, pueden tener copias de los datos o puede compartir un modelo de vista que pueden usar para obtener el último estado de un objeto.

La introducción de la integridad referencial reintroducirá el acoplamiento, en su lugar, querrá usar algo como Guids para sus claves primarias, serán creadas por el creador del objeto, el resto se trata de administrar la consistencia eventual.

Eche un vistazo a la charla de Udi Dahan en NDC Oslo para obtener más detalles.

Espero que esto ayude

Sean Farmar
fuente
2
El enlace de la charla de Udi Dahan es muy interesante
Comencau
3

primera solución: Composición API

 Implement a query by defining an API Composer, which invoking the
 services that own the data and performs an in-memory join of the
 results

ingrese la descripción de la imagen aquí

segunda solución: CQRS

Define a view database, which is a read-only replica that is designed to support that 
query. The application keeps the replica up to data by subscribing to Domain events 
published by the service that own the data.

ingrese la descripción de la imagen aquí

Ali_Hr
fuente
1

Una actualización de 2020 para esta respuesta es utilizar una herramienta de captura de datos modificados como Debezium. Debezium monitoreará las tablas de su base de datos en busca de cambios y las transmitirá a Kafka / Pulsar (otras tuberías) y sus suscriptores pueden capturar los cambios y sincronizarlos.

user521990
fuente