Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Patrón de capa anticorrupción
Intención
El patrón de capa anticorrupción (ACL) actúa como una capa de mediación que traduce la semántica del modelo de dominio de un sistema a otro. Traduce el modelo del contexto limitado ascendente (monolito) en un modelo que se adapte al contexto limitado descendente (microservicio) antes de consumir el contrato de comunicación establecido por el equipo de origen. Este patrón puede aplicarse cuando el contexto acotado descendente contiene un subdominio principal o el modelo ascendente es un sistema heredado no modificable. También reduce el riesgo de transformación y la interrupción del negocio al evitar cambios en las personas que llaman cuando sus llamadas deben redirigirse de forma transparente al sistema de destino.
Motivación
Durante el proceso de migración, cuando una aplicación monolítica se migra a microservicios, es posible que se produzcan cambios en la semántica del modelo de dominio del servicio recién migrado. Cuando las funciones del monolito sean necesarias para llamar a estos microservicios, las llamadas deben enrutarse al servicio migrado sin necesidad de realizar ningún cambio en los servicios de llamadas. El patrón ACL permite que el monolito llame a los microservicios de forma transparente al actuar como un adaptador o una capa de fachada que traduce las llamadas a la semántica más nueva.
Aplicabilidad
Considere la posibilidad de utilizar este patrón cuando:
-
La aplicación monolítica existente debe comunicarse con una función que se ha migrado a un microservicio, y el modelo y la semántica del dominio de servicio migrado difieren de los de la función original.
-
Dos sistemas tienen una semántica diferente y necesitan intercambiar datos, pero no es práctico modificar un sistema para que sea compatible con el otro.
-
Desea utilizar un enfoque rápido y simplificado para adaptar un sistema a otro con un impacto mínimo.
-
La aplicación se está comunicando con un sistema externo.
Cuestiones y consideraciones
-
Dependencias del equipo:Cuando diferentes servicios de un sistema son propiedad de diferentes equipos, la semántica del nuevo modelo de dominio en los servicios migrados puede provocar cambios en los sistemas de llamadas. Sin embargo, es posible que los equipos no puedan realizar estos cambios de forma coordinada, porque es posible que tengan otras prioridades. La ACL desacopla las llamadas y las traduce para que coincidan con la semántica de los nuevos servicios, evitando así la necesidad de que las personas que llaman realicen cambios en el sistema actual.
-
Gastos operativos:El patrón de ACL requiere un esfuerzo adicional para funcionar y mantenerse. Este trabajo incluye la integración de la ACL con las herramientas de monitoreo y alerta, el proceso de lanzamiento y los procesos de integración y entrega continuas (CI/CD).
-
Punto único de fallo:Cualquier error en la ACL puede hacer que el servicio de destino sea inalcanzable y provocar problemas en la aplicación. Para mitigar este problema, debe incorporar capacidades de reintento y disyuntores. Consulte elreintentar con backoffydisyuntorpatrones para entender más acerca de estas opciones. La configuración de las alertas y el registro adecuados mejorarán el tiempo medio de resolución (MTTR).
-
Deuda técnica:Como parte de su estrategia de migración o modernización, considere si la ACL será una solución transitoria o provisional, o una solución a largo plazo. Si se trata de una solución provisional, debe registrar la ACL como una deuda técnica y retirarla de servicio una vez que se hayan migrado todas las personas dependientes que llamen.
-
Latencia:La capa adicional puede introducir latencia debido a la conversión de solicitudes de una interfaz a otra. Le recomendamos que defina y pruebe la tolerancia de rendimiento en las aplicaciones que son sensibles al tiempo de respuesta antes de implementar la ACL en los entornos de producción.
-
Cuello de botella escalable:En las aplicaciones de alta carga en las que los servicios se pueden escalar hasta alcanzar los picos de carga, la ACL puede convertirse en un obstáculo y provocar problemas de escalado. Si el servicio de destino se escala según la demanda, debe diseñar la ACL para que se escale en consecuencia.
-
Implementación compartida o específica del servicio:Puede diseñar la ACL como un objeto compartido para convertir y redirigir las llamadas a varios servicios o clases específicas de un servicio. Tenga en cuenta la latencia, el escalado y la tolerancia a errores al determinar el tipo de implementación de la ACL.
Implementación
Puede implementar la ACL dentro de su aplicación monolítica como una clase específica del servicio que se está migrando o como un servicio independiente. La ACL debe retirarse después de que todos los servicios dependientes se hayan migrado a la arquitectura de microservicios.
Arquitectura de alto nivel
En la siguiente arquitectura de ejemplo, una aplicación monolítica tiene tres servicios: servicio de usuario, servicio de carrito y servicio de cuentas. El servicio de carrito depende del servicio de usuario y la aplicación utiliza una base de datos relacional monolítica.
En la siguiente arquitectura, el servicio de usuario se ha migrado a un nuevo microservicio. El servicio de carrito llama al servicio de usuario, pero la implementación ya no está disponible dentro del monolito. También es probable que la interfaz del servicio recién migrado no coincida con su interfaz anterior, cuando estaba dentro de la aplicación monolítica.
Si el servicio de carrito tiene que llamar directamente al servicio de usuario recién migrado, será necesario realizar cambios en el servicio de carrito y probar exhaustivamente la aplicación monolítica. Esto puede aumentar el riesgo de transformación y la interrupción del negocio. El objetivo debe ser minimizar los cambios en la funcionalidad existente de la aplicación monolítica.
En este caso, le recomendamos que introduzca una ACL entre el servicio de usuario anterior y el servicio de usuario recién migrado. La ACL funciona como un adaptador o una fachada que convierte las llamadas en la interfaz más nueva. La ACL se puede implementar dentro de la aplicación monolítica como una clase (por ejemplo,UserServiceFacade
oUserServiceAdapter
) que es específico del servicio que se ha migrado. La capa anticorrupción debe retirarse después de que todos los servicios dependientes se hayan migrado a la arquitectura de microservicios.
Implementación medianteAWSservicios
El siguiente diagrama muestra cómo puede implementar este ejemplo de ACL medianteAWSservicios.
El microservicio de usuario se migra de la aplicación monolítica de ASP.NET y se implementa comoAWS Lambda
¿Cuándo?Program.cs
llama al servicio de usuario (UserInMonolith.cs
) dentro del monolito, la llamada se enruta a la ACL (UserServiceACL.cs
). La ACL traduce la llamada a la nueva semántica e interfaz y llama al microservicio a través del punto final de API Gateway. La persona que llama (Program.cs
) no conoce la traducción y el enrutamiento que tienen lugar en el servicio de usuario y en la ACL. Como la persona que llama no está al tanto de los cambios en el código, hay menos interrupciones en el negocio y un menor riesgo de transformación.
Código de muestra
El siguiente fragmento de código proporciona los cambios en el servicio original y la implementación deUserServiceACL.cs
. Cuando se recibe una solicitud, el servicio de usuario original llama a la ACL. La ACL convierte el objeto de origen para que coincida con la interfaz del servicio recién migrado, llama al servicio y devuelve la respuesta a la persona que llama.
public class UserInMonolith: IUserInMonolith { private readonly IACL _userServiceACL; public UserInMonolith(IACL userServiceACL) => (_userServiceACL) = (userServiceACL); public async Task<HttpStatusCode> UpdateAddress(UserDetails userDetails) { //Wrap the original object in the derived class var destUserDetails = new UserDetailsWrapped("user", userDetails); //Logic for updating address has been moved to a microservice return await _userServiceACL.CallMicroservice(destUserDetails); } } public class UserServiceACL: IACL { static HttpClient _client = new HttpClient(); private static string _apiGatewayDev = string.Empty; public UserServiceACL() { IConfiguration config = new ConfigurationBuilder().AddJsonFile(AppContext.BaseDirectory + "../../../config.json").Build(); _apiGatewayDev = config["APIGatewayURL:Dev"]; _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); } public async Task<HttpStatusCode> CallMicroservice(ISourceObject details) { _apiGatewayDev += "/" + details.ServiceName; Console.WriteLine(_apiGatewayDev); var userDetails = details as UserDetails; var userMicroserviceModel = new UserMicroserviceModel(); userMicroserviceModel.UserId = userDetails.UserId; userMicroserviceModel.Address = userDetails.AddressLine1 + ", " + userDetails.AddressLine2; userMicroserviceModel.City = userDetails.City; userMicroserviceModel.State = userDetails.State; userMicroserviceModel.Country = userDetails.Country; if (Int32.TryParse(userDetails.ZipCode, out int zipCode)) { userMicroserviceModel.ZipCode = zipCode; Console.WriteLine("Updated zip code"); } else { Console.WriteLine("String could not be parsed."); return HttpStatusCode.BadRequest; } var jsonString = JsonSerializer.Serialize<UserMicroserviceModel>(userMicroserviceModel); var payload = JsonSerializer.Serialize(userMicroserviceModel); var content = new StringContent(payload, Encoding.UTF8, "application/json"); var response = await _client.PostAsync(_apiGatewayDev, content); return response.StatusCode; } }
GitHubrepositorio
Para obtener una implementación completa de la arquitectura de ejemplo para este patrón, consulteGitHubrepositorio enhttps://github.com/aws-samples/anti-corruption-layer-pattern