¿Cuál es la estrategia de transacción más aceptada para microservicios?

71

Uno de los principales problemas que he visto en un sistema con microservicios es la forma en que funcionan las transacciones cuando abarcan diferentes servicios. Dentro de nuestra propia arquitectura, hemos estado usando transacciones distribuidas para resolver esto, pero vienen con sus propios problemas. Especialmente los puntos muertos han sido un dolor hasta ahora.

Otra opción parece ser algún tipo de administrador de transacciones hecho a medida, que conoce los flujos dentro de su sistema y se hará cargo de las reversiones como un proceso en segundo plano que abarca todo su sistema (por lo que le dirá al otro servicios para revertir y si están fuera de servicio, notifíquelos más adelante).

¿Hay otra opción aceptada? Ambos parecen tener sus desventajas. El primero podría causar puntos muertos y un montón de otros problemas, el segundo podría resultar en una inconsistencia de los datos. ¿Hay mejores opciones?

    
pregunta Kristof 27.07.2015 - 07:13

7 respuestas

36

El enfoque habitual es aislar esos microservicios tanto como sea posible, tratarlos como unidades individuales. Luego, las transacciones pueden desarrollarse en el contexto del servicio en su totalidad (es decir, no es parte de las transacciones de DB habituales, aunque aún puede tener transacciones de DB internas al servicio).

Piense cómo se producen las transacciones y qué tipo tiene sentido para sus servicios, entonces puede implementar un mecanismo de reversión que deshaga la operación original, o un sistema de confirmación de dos fases que reserve la operación original hasta que se le indique que se comprometa de verdad. Por supuesto, ambos sistemas significan que estás implementando los tuyos, pero luego ya estás implementando tus microservicios.

Los servicios financieros hacen este tipo de cosas todo el tiempo: si quiero transferir dinero de mi banco a su banco, no hay una transacción única como la que tendría en una base de datos. No sabe qué sistemas está ejecutando ninguno de los dos bancos, por lo que debe tratar cada uno como sus microservicios. En este caso, mi banco movería mi dinero de mi cuenta a una cuenta de tenencia y luego le diría a su banco que tiene algo de dinero. Si ese envío falla, mi banco reembolsará mi cuenta con el dinero que intentó enviar.

    
respondido por el gbjbaanb 27.07.2015 - 14:41
27

Creo que la sabiduría estándar es nunca tener transacciones que crucen los límites de microservicio. Si un conjunto determinado de datos realmente necesita ser atómicamente coherente con otro, esas dos cosas van juntas.

Esta es una de las razones por las que es muy difícil dividir un sistema en servicios hasta que lo haya diseñado por completo. Lo que en el mundo moderno probablemente significa escrito ...

    
respondido por el soru 27.07.2015 - 09:00
16

Creo que si la consistencia es un requisito importante en su aplicación, debería preguntarse si los microservicios son el mejor enfoque. Al igual que Martin Fowler, dice :

  

Los microservicios introducen eventuales problemas de coherencia debido a su elogiosa insistencia en la gestión descentralizada de datos. Con un monolito, puedes actualizar un montón de cosas juntas en una sola transacción. Los microservicios requieren múltiples recursos para actualizar, y las transacciones distribuidas son mal vistas (por una buena razón). Así que ahora, los desarrolladores deben ser conscientes de los problemas de consistencia y descubrir cómo detectar cuándo las cosas no están sincronizadas antes de hacer algo que el código lamentará.

Pero quizás en su caso, puede sacrificar la Consistencia en pos de Disponibilidad

  

Los procesos comerciales a menudo son más tolerantes a las inconsistencias de lo que cree, porque las empresas a menudo valoran más la disponibilidad.

Sin embargo, también me pregunto si existe una estrategia para transacciones distribuidas en microservicios, pero tal vez el costo sea demasiado alto. Quería darte mis dos centavos con el siempre excelente artículo de Martin Fowler y la CAP teorema.

    
respondido por el gabrielgiussi 27.07.2015 - 14:00
14

Como se sugiere en al menos una de las respuestas aquí, pero también en otras partes de la web, es posible diseñar un microservicio que persiga a las entidades dentro de una transacción normal si necesita coherencia entre las dos entidades.

Pero al mismo tiempo, es posible que tenga una situación en la que las entidades realmente no pertenezcan al mismo microservicio, por ejemplo, registros de ventas y registros de pedidos (cuando ordena algo para completar la venta). En tales casos, es posible que necesite una forma de garantizar la coherencia entre los dos microservicios.

Las transacciones distribuidas tradicionalmente se han utilizado y, según mi experiencia, funcionan bien hasta que alcanzan un tamaño en el que el bloqueo se convierte en un problema. Puede relajar el bloqueo para que realmente solo los recursos relevantes (p. Ej., El artículo que se vende) se "bloqueen" mediante un cambio de estado, pero aquí es donde comienza a complicarse porque está ingresando al territorio donde necesita construir todos los recursos. lógica para hacer esto, usted mismo, en lugar de tener, digamos que una base de datos lo maneja por usted.

He trabajado con compañías que han optado por crear su propio marco de transacciones para manejar este complejo problema, pero no lo recomiendo porque es costoso y requiere tiempo para madurar.

Hay productos por ahí que pueden ser conectados a su sistema que cuidan la consistencia. Un motor de procesos de negocios es un buen ejemplo y, por lo general, manejan la consistencia eventualmente y mediante el uso de compensaciones. Otros productos funcionan de manera similar. Por lo general, termina con una capa de software cerca del cliente (s), que se ocupa de la coherencia y las transacciones y los servicios (micro) de llamadas para realizar el procesamiento empresarial real . Uno de estos productos es un conector JCA genérico que se puede usar con soluciones Java EE (para transparencia: soy el autor). Consulte enlace para obtener más detalles y una discusión más profunda de los problemas planteados aquí.

Otra forma de manejar las transacciones y la consistencia es envolver una llamada a un microservicio en una llamada a algo transaccional como una cola de mensajes. Tome el ejemplo de registro de ventas / registro de pedidos de arriba: puede simplemente dejar que el microservicio de ventas envíe un mensaje al sistema de pedidos, que se confirma en la misma transacción que registra la venta en la base de datos. El resultado es una solución asíncrona que se escala muy bien muy . Utilizando tecnologías como sockets web, puede incluso solucionar el problema del bloqueo, que a menudo está relacionado con la ampliación de soluciones asíncronas. Para obtener más ideas sobre patrones como este, vea otro de mis artículos: enlace .

Cualquiera que sea la solución que termines eligiendo, es importante reconocer que solo una pequeña parte de tu sistema escribirá cosas que deben ser coherentes; es probable que la mayoría del acceso sea de solo lectura. Por esa razón, cree la gestión de transacciones solo en las partes relevantes del sistema, de modo que aún pueda escalar bien.

    
respondido por el Ant Kutschera 15.08.2015 - 10:36
1

En microservicios hay tres formas de lograr consistencia entre diferencias. servicios:

  1. Orquestación: un proceso que administra la transacción y la reversión entre servicios.

  2. Coreografía: el servicio pasa los mensajes entre sí y finalmente alcanza un estado coherente.

  3. Híbrido: mezcla los dos anteriores.

Para una lectura completa, vaya al enlace: enlace

    
respondido por el techagrammer 08.02.2018 - 07:21
0

Comenzaría con la descomposición del espacio problemático: identificando sus límites de servicio . Cuando se hace correctamente, nunca necesitaría realizar transacciones entre servicios.

Los diferentes servicios tienen sus propios datos, comportamiento, fuerzas motivacionales, gobierno, reglas comerciales, etc. Un buen comienzo es enumerar qué capacidades de alto nivel tiene su empresa. Por ejemplo, marketing, ventas, contabilidad, soporte. Otro punto de partida es la estructura organizativa, pero tenga en cuenta que existe una advertencia: por alguna razón (política, por ejemplo), podría no ser el esquema óptimo de descomposición empresarial. Un enfoque más estricto es el análisis de la cadena de valor . Recuerde, sus servicios también pueden incluir personas, no es estrictamente software. Los servicios deben comunicarse entre sí a través de eventos .

El siguiente paso es tallar estos servicios. Como resultado, sigue siendo relativamente independiente agregados . Representan una unidad de consistencia. En otras palabras, sus partes internas deben ser consistentes y ACID. Los agregados se comunican entre ellos mediante eventos.

Si piensa que su dominio exige consistencia primero, piénselo nuevamente. Ninguno de los sistemas grandes y de misión crítica se construyen con esto en mente. Todos ellos son distribuidos y eventualmente consistentes. Consulte el papel clásico de Pat Helland .

Aquí hay algunos consejos prácticos sobre cómo construir un sistema distribuido. .

    
respondido por el Zapadlo 11.09.2017 - 15:56
0

Hay muchas soluciones que comprometen más de lo que me siento cómodo. Por supuesto, si su caso de uso es complejo, como mover dinero entre diferentes bancos, las alternativas más agradables pueden ser imposibles. Pero echemos un vistazo a lo que podemos hacer en el escenario común, donde el uso de microservicios interfiere con nuestras posibles transacciones de base de datos.

Opción 1: evite la necesidad de transacciones si es posible

Obvio y mencionado anteriormente, pero ideal si podemos manejarlo. ¿Pertenecían realmente los componentes al mismo microservicio? ¿O podemos rediseñar el (los) sistema (s) para que la transacción se vuelva innecesaria? Quizás aceptar el no sacrificio es el sacrificio más asequible.

Opción 2: usar una cola

Si hay suficiente certeza de que el otro servicio tendrá éxito en lo que queramos que haga, podemos llamarlo a través de alguna forma de cola. El elemento en cola no se recogerá hasta más tarde, pero podemos asegurarnos de que el elemento esté en cola .

Por ejemplo, digamos que queremos insertar una entidad y enviar un correo electrónico, como una sola transacción. En lugar de llamar al servidor de correo, colocamos el correo en una tabla.

Begin transaction
Insert entity
Insert e-mail
Commit transaction

Un claro inconveniente es que varios microservicios necesitarán acceso a la misma tabla.

Opción 3: haga el trabajo externo en último lugar, justo antes de completar la transacción

Este enfoque se basa en el supuesto de que es muy poco probable que la transacción se cometa.

Begin transaction
Insert entity
Insert another entity
Make external call
Commit transaction

Si las consultas fallan, la llamada externa aún no se ha realizado. Si la llamada externa falla, la transacción nunca se confirma.

Este enfoque viene con las limitaciones de que solo podemos hacer una llamada externa, y debe hacerse en último lugar (es decir, no podemos usar su resultado en nuestras consultas).

Opción 4: crear cosas en un estado pendiente

Como se publicó aquí , podemos hacer que varios microservicios creen diferentes componentes, cada uno en un estado pendiente, sin transacciones.

Se realiza cualquier validación, pero nada se crea en un estado definitivo. Después de que todo ha sido creado exitosamente, cada componente es activado. Por lo general, esta operación es tan simple y las probabilidades de que algo salga mal son tan pequeñas, que incluso podemos preferir realizar la activación sin transacciones.

El mayor inconveniente es probablemente que tenemos que tener en cuenta la existencia de elementos pendientes. Cualquier consulta de selección debe considerar si se deben incluir los datos pendientes. La mayoría debería ignorarlo. Y las actualizaciones son otra historia en conjunto.

Opción 5: permitir que el microservicio comparta su consulta

¿Ninguna de las otras opciones lo hace por ti? Entonces pongámonos heterodoxos .

Dependiendo de la compañía, esta puede ser inaceptable. Soy consciente. Esto es poco ortodoxo. Si no es aceptable, sigue otra ruta. Pero si esto se ajusta a su situación, resuelve el problema de manera simple y poderosa. Podría ser el compromiso más aceptable.

Hay una forma de convertir las consultas de múltiples microservicios en una transacción simple y única de base de datos.

Devuelva la consulta, en lugar de ejecutarla.

Begin transaction
Execute our own query
Make external call, receiving a query
Execute received query
Commit transaction

En cuanto a la red, cada microservicio debe poder acceder a cada base de datos. Tenga esto en cuenta, también con respecto a la escala futura.

Si las bases de datos involucradas en la transacción están en el mismo servidor, esta será una transacción regular. Si están en servidores diferentes, será una transacción distribuida. El código es el mismo independientemente.

Recibimos la consulta, incluido su tipo de conexión, sus parámetros y su cadena de conexión. Podemos envolverlo en una ordenada clase de comando ejecutable, manteniendo el flujo legible: el llamado al microservicio resulta en un comando, que ejecutamos, como parte de nuestra transacción.

La cadena de conexión es lo que nos brinda el microservicio de origen, por lo que para todos los propósitos y propósitos, la consulta aún se considera ejecutada por ese microservicio. Solo lo estamos enrutando físicamente a través del microservicio del cliente. Eso hace una diferencia? Bueno, nos permite ponerlo en la misma transacción con otra consulta.

Si el compromiso es aceptable, este enfoque nos da la transaccionalidad simple de una aplicación de monolito, en una arquitectura de microservicio.

    
respondido por el Timo 23.05.2018 - 14:44

Lea otras preguntas en las etiquetas