Microservicios sin duplicación de datos.

19

Me resulta difícil evitar la duplicación de datos o una base de datos compartida, incluso para el diseño de microservicios más simple, lo que me hace pensar que me falta algo. Aquí hay un ejemplo básico del problema que estoy enfrentando. Asumiendo que alguien está usando una aplicación web para administrar un inventario, necesitaría dos servicios; uno para el inventario que administra los artículos y la cantidad en stock y un servicio de usuarios que administraría los datos de los usuarios. Si queremos una auditoría de quién almacenó la base de datos, podríamos agregar el ID de usuario a la base de datos para el servicio de inventario como último inventario por valor.

Al usar la aplicación, es posible que queramos ver todos los artículos que se están agotando, y una lista de quién los almacenó la última vez para que podamos pedirles que lo repongan nuevamente. Utilizando la arquitectura descrita anteriormente, se realizaría una solicitud al servicio de inventario para recuperar los detalles del artículo de todos los artículos en los que la cantidad es inferior a 5. Esto devolvería una lista que incluye los ID de usuario. Luego, se realizaría una solicitud por separado al servicio de usuarios para obtener el nombre de usuario y los detalles de contacto para la lista de ID de usuario obtenida del servicio de inventario.

Esto parece terriblemente ineficiente y no se necesitan muchos más servicios antes de realizar múltiples solicitudes a diferentes API de servicios, que a su vez realizan múltiples consultas a la base de datos. Una alternativa es replicar los detalles de los usuarios en los datos del inventario. Cuando un usuario cambia sus datos de contacto, deberíamos replicar el cambio a través de todos los demás servicios. Pero esto no parece encajar con la idea de contexto acotado de los microservicios. También podríamos usar una sola base de datos y compartirla entre diferentes servicios, y tener todos los problemas de una base de datos de integración .

¿Cuál es la forma correcta / mejor de implementar esto?

Geraint Anderson
fuente
55
Bienvenido a la paradoja de los microservicios. Lo que parecería simplificar las cosas puede hacer que las cosas sean más complejas.
Robert Harvey
La forma "correcta" es la misma de siempre: encuentra la forma de hacer las cosas que mejor se adapte a tus objetivos específicos.
Robert Harvey
1
@RobertHarvey Ese es siempre el caso, pero estoy tratando de entender la forma de los microservicios de libros de texto. Una vez que comprenda cómo debería funcionar en un mundo ideal, lo cambiaré felizmente para que se ajuste a mi caso de uso.
Geraint Anderson
1
Pero está formulando su pregunta en términos de eficiencia, que es un requisito de software no funcional. La forma de resolver el problema de eficiencia es preguntando directamente a la base de datos.
Robert Harvey
1
Estaba a punto de escribir una pregunta exactamente como la suya. Todavía no veo ventajas en MSA para aplicaciones web razonablemente simples. Creo que en muchos casos se podría lograr la modularidad sin hacer las cosas tan complejas.
Glasnhost

Respuestas:

10

Extrañé por completo dónde se te pide que dupliques.

Un principio central de los microservicios es que el servicio sea la autoridad única. Eso significa que el inventario y la gestión de usuarios pueden estar completamente separados. Diseñaría la gestión de usuarios para que ni siquiera sepa que existe el sistema de inventario.

Pero diseñaría el sistema de inventario para que nunca almacene nada sobre los usuarios que no sea una identificación de usuario. Eso se ocupa de su problema de propagar los cambios de información del usuario.

En cuanto a las cosas que necesitan información de inventario e información del usuario, como registros, auditorías e impresiones, no se actualizan a medida que la información cambia. Son un registro de lo que fue. De nuevo, no propagas el cambio.

Entonces, en todos los casos, cuando desea la información de usuario más reciente, solicita el servicio de información de usuario.

naranja confitada
fuente
@Geraint: ¿Puede ser más específico sobre qué tipo de duplicación está ocurriendo en su sistema?
Robert Harvey
1
Gracias. La duplicación se refería a copiar los detalles de contacto de los usuarios en el servicio de inventario, pero usted lo ha abordado (es decir, no es obligatorio). Parece contrario a la intuición pasar de una única base de datos relacional donde podría obtener los datos de inventario y los datos del usuario con una combinación para hacer dos llamadas API diferentes donde la segunda no puede comenzar hasta que la primera haya devuelto los resultados. Pero supongo que eso es parte de la evaluación de si uso microservicios u otra cosa.
Geraint Anderson
Es el mismo truco que el DB usaría si lograra ambos. No copie la información del usuario en la tabla de inventario. Le das una clave foránea. La ID de usuario está haciendo el mismo trabajo en todos los servicios. Solo hazlo único.
candied_orange
It seems counter-intuitive to move from a single relational database where I could get the inventory data and the user data with a joinTenga en cuenta que "idealmente" hay una tienda por servicio (¡o más!). Por lo tanto, no hay nada como "unirse" entre "límites". La razón es simple, DB genera acoplamiento entre servicios. A diferencia de la sugerencia de @CandiedOrange, creo que podemos duplicar un mínimo de datos de un servicio a otro. Me refiero a datos que es poco probable que cambien. Si este duplicado mejora la eficiencia y el rendimiento (y se requieren ambos), los "profesionales" probablemente compensarían los "contras"
Laiv
@GeraintAnderson Quiero decir, si necesita eficiencia (que es, por definición, un requisito no funcional), hay formas de hacerlo. Es decir, solicitar páginas de datos del Servicio de inventario (como 10 elementos), tomar cada página y usar esa página para solicitar datos del Servicio de usuario, y agregar al final. De esa forma, mantiene sus límites mientras aprovecha el paralelismo de los servicios independientes. Incluso entonces, no se moleste hasta que lo haya identificado como un verdadero cuello de botella de la aplicación que debe resolverse: esperar 1/2 segundo adicional en un trabajo nocturno de 1 segundo no le importa a nadie.
Delioth
11

Me resulta difícil evitar la duplicación de datos ...

Según el ebook de Microsoft sobre arquitectura de microservicios , no hay nada de malo en la duplicación de datos. Básicamente, la duplicación de datos aumenta el desacoplamiento entre los servicios y, por lo tanto, fortalece sus roles como una autoridad única. Un pasaje relevante:

Y finalmente (y aquí es donde surgen la mayoría de los problemas cuando se construyen microservicios), si su microservicio inicial necesita datos que originalmente pertenecen a otros microservicios, no confíe en hacer solicitudes sincrónicas para esos datos. En su lugar, replique o propague esos datos (solo los atributos que necesita) en la base de datos del servicio inicial usando la consistencia eventual (típicamente usando eventos de integración ...

Maurits Moeys
fuente
1
Estoy en completo desacuerdo. Hace que sea más difícil de mantener. Le hace implementar transacciones entre microservicios cuando algo debe agregarse, actualizarse o eliminarse. En caso de que desee evitar un solo punto de falla, puede usar request o cualquier otro tipo de almacenamiento en caché.
Alan Sereb
1
@AlanSereb Es más difícil de mantener, pero el punto es que a veces no tienes otra opción. Por ejemplo, ¿qué pasa si necesita hacer un FK entre objetos que viven en dos bases de datos? La única forma de garantizar la coherencia al realizar consultas en una base de datos local es tener una replicación de datos. Eche un vistazo a: stackoverflow.com/a/4452586/2255491
David D.
Estoy de acuerdo. Otro gran enfoque es tomar la ruta de abastecimiento de eventos. Y haga que todas las mutaciones se ejecuten a través del canal de eventos
haga canal de Alan Sereb,
4

se realizaría una solicitud al servicio de inventario para recuperar los detalles del artículo de todos los artículos donde la cantidad es inferior a 5. Esto devolvería una lista que incluye las ID de usuario. Luego, se realizaría una solicitud por separado al servicio de usuarios para obtener el nombre de usuario y los detalles de contacto para la lista de ID de usuario obtenida del servicio de inventario.

De hecho si.

De acuerdo, en un monolito podría tener un modelo de inventario al que consulta los elementos relevantes, introducirlo en un modelo de usuario y obtener los mismos datos.

O podría llevarlo más lejos, si los tiene en la misma base de datos relacional y escribe SQL y la base de datos tomará la tabla de inventario y la tabla de usuario, hace algo de magia y obtiene los datos que busca.

Independientemente de cómo lo hagas, en algún lugar habrá un código que esencialmente obtiene una lista de identificadores de usuario del sistema de inventario, los introduce en el sistema de usuario y compila una lista de datos.

La pregunta que debe responder es sobre el rendimiento y el mantenimiento y otras cualidades "suaves".

El principal beneficio de los microservicios es el escalado.Si tiene diez mil usuarios en una máquina y es un poco lento, puede agregar otra máquina y el sistema se vuelve el doble de rápido. Agregue ocho más y es diez veces más rápido. (La escala lineal es probablemente optimista, pero es lo ideal y no eso irracional esperar).

Y esto es por servicio . Si el sistema de inventario es el cuello de botella, se usa para más que informes sobre usuarios, puede agregar más máquinas solo a ese servicio . Las máquinas también pueden ser especializadas; Este servicio necesita mucha memoria, hace cálculos pesados ​​y necesita más CPU.

Si no necesita el escalado, hay otro beneficio de los microservicios: son modulares . Por supuesto, las aplicaciones monolíticas también pueden ser modulares, y tiene una base de datos normalizada y ... pero en la práctica, las paredes entre módulos son como paredes de vidrio en el mejor de los casos y líneas en la arena en el peor de los casos. Los microservicios están separados por acero sólido.

Si su sistema de usuario literalmente se incendia, eso no afectará a su sistema de inventario en lo más mínimo. No podrá imprimir informes bonitos sobre quién almacenó qué, pero los clientes podrán realizar pedidos seguros sabiendo que los artículos almacenados están allí.

Y no duplica datos en microservicios , como tampoco lo hace en una base de datos relacional (*). En una base de datos relacional puede hacer una unión , y el equivalente es fusionar las listas en código como se describe.

También puedes agregar una vista , el equivalente es agregar un nuevo servicio que combine por usted; eso resultaría en tres solicitudes; uno para el nuevo servicio y luego ese servicio hace los dos originales. Las bases de datos relacionales tienen elementos sofisticados que optimizan las vistas, que deben implementarse en el nivel de servicio. No lo obtienes "gratis".

El almacenamiento en caché es diferente de la duplicación de datos en que si dos valores no coinciden, usted sabe cuál está mal. A menudo se usa en microservicios para aumentar la disponibilidad a expensas de la coherencia (teorema CAP). Dado que las bases de datos relacionales eliminan completamente la disponibilidad en el altar de la consistencia, es menos común en ellas. Diría que no hay nada inherente en los microservicios que facilite el almacenamiento en caché, pero en la práctica el almacenamiento en caché es una preocupación principal y que facilita el almacenamiento en caché en microservicios .

(*) Si tiene sentido duplicar datos en un enjambre de microservicios, entonces probablemente tendría sentido en la base de datos relacional equivalente a.

Odalrick
fuente
3
Realmente me gustó su respuesta hasta la parte "no duplicar datos en microservicios". Creo que hay casos en los que la duplicación de datos es el enfoque correcto. Mejora la tolerancia a fallos y la autonomía. Si el servicio de usuario dejó de funcionar, el servicio de inventario aún puede mostrar una lista de inventario bajo con quién los almacenó en último lugar.
Peter Pompeya
1
@peterpompeii Yo llamaría a eso almacenamiento en caché, no duplicación de datos. La duplicación de datos es cuando tiene dos lugares para actualizar para un dato, almacenamiento en caché cuando hay un lugar y propagación automática a los otros lugares. También dije más que relacional. Si tiene sentido en una base de datos relacional duplicar datos, tiene sentido en un microservicio. Creo que estamos de acuerdo y esa parte podría ser más clara, pero solo tengo un teléfono en este momento, así que no actualizaré el texto en este momento.
Odalrick
@PeterPompeii Espero que la sección adicional sobre el almacenamiento en caché aborde algunas de sus preocupaciones.
Odalrick
1
@Odalrick lo que describiste suena como replicación de datos. La replicación y el almacenamiento en caché son dos formas de duplicar datos. La replicación es cuando se garantiza que una copia siempre tenga todos los datos necesarios. El almacenamiento en caché es bajo demanda. El almacenamiento en caché puede fallar. El almacenamiento en caché por disponibilidad no tiene tanto sentido como el almacenamiento en caché por rendimiento. TL; DR si está almacenando una copia completa de algo con suficiente consistencia garantiza que nunca necesitará verificar errores, entonces no es un caché.
Brandon el
1
@Brandon Otra diferencia entre la replicación y el almacenamiento en caché es cómo sabe qué datos están mal cuando hay una diferencia. La replicación define algunas reglas sobre cómo fusionar los datos. El almacenamiento en caché por otro lado es siempre : el caché está mal.
Odalrick