Hay muchas soluciones que comprometen más de lo que me siento cómodo. De acuerdo, si su caso de uso es complejo, como mover dinero entre diferentes bancos, 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 bases de datos.
Opción 1: evite la necesidad de transacciones si es posible
Obvio y mencionado antes, pero ideal si podemos manejarlo. ¿Los componentes pertenecían realmente al mismo microservicio? ¿O podemos rediseñar los sistemas de manera que la transacción se vuelva innecesaria? Quizás aceptar la no transaccionalidad 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 hagamos, podemos llamarlo a través de algún tipo de cola. El artículo en cola no se recogerá hasta más tarde, pero podemos asegurarnos de que esté en cola .
Por ejemplo, supongamos 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 inconveniente claro es que múltiples microservicios necesitarán acceso a la misma tabla.
Opción 3: hacer el trabajo externo al final, justo antes de completar la transacción
Este enfoque se basa en el supuesto de que es muy improbable que la transacción se confirme.
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 estado pendiente
Como se publicó aquí , podemos hacer que múltiples microservicios creen diferentes componentes, cada uno en un estado pendiente, no transaccional.
Se realiza cualquier validación, pero nada se crea en un estado definitivo. Después de que todo se haya creado con éxito, cada componente se activa. 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 hacer la activación de manera no transaccional.
El mayor inconveniente es probablemente que tenemos que tener en cuenta la existencia de elementos pendientes. Cualquier consulta de selección debe considerar si incluir datos pendientes. La mayoría debería ignorarlo. Y las actualizaciones son otra historia por completo.
Opción 5: dejar que el microservicio comparta su consulta
¿Ninguna de las otras opciones lo hace por ti? Entonces seamos poco ortodoxos .
Dependiendo de la compañía, esta puede ser inaceptable. Soy consciente. Esto no es ortodoxo. Si no es aceptable, toma 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 manera de convertir las consultas de múltiples microservicios en una transacción de base de datos simple y única.
Devuelve 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 clase de comando ejecutable ordenada, manteniendo el flujo legible: la llamada al microservicio da como resultado un comando, que ejecutamos, como parte de nuestra transacción.
La cadena de conexión es lo que nos proporciona el microservicio de origen, por lo que, para todos los efectos, el microservicio todavía considera que la consulta se ejecuta. Simplemente 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 brinda la transaccionalidad directa de una aplicación monolítica, en una arquitectura de microservicio.