Schema a strati anticorruzione - AWS Guida prescrittiva

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Schema a strati anticorruzione

Intento

Il pattern anticorruzione (ACL) funge da livello di mediazione che traduce la semantica del modello di dominio da un sistema all'altro. Traduce il modello del contesto limitato a monte (monolite) in un modello adatto al contesto limitato a valle (microservizio) prima di utilizzare il contratto di comunicazione stabilito dal team a monte. Questo modello può essere applicabile quando il contesto limitato a valle contiene un sottodominio principale o il modello a monte è un sistema legacy non modificabile. Riduce inoltre il rischio di trasformazione e le interruzioni dell'attività impedendo ai chiamanti di modificare le chiamate quando devono essere reindirizzate in modo trasparente al sistema di destinazione.

Motivazione

Durante il processo di migrazione, quando un'applicazione monolitica viene migrata nei microservizi, potrebbero verificarsi cambiamenti nella semantica del modello di dominio del servizio appena migrato. Quando sono necessarie le funzionalità all'interno del monolite per chiamare questi microservizi, le chiamate devono essere indirizzate al servizio migrato senza richiedere alcuna modifica ai servizi chiamanti. Il pattern ACL consente al monolite di chiamare i microservizi in modo trasparente agendo come un adattatore o uno strato di facciata che traduce le chiamate nella semantica più recente.

Applicabilità

Prendi in considerazione l'utilizzo di questo modello quando:

  • L'applicazione monolitica esistente deve comunicare con una funzione che è stata migrata in un microservizio e il modello e la semantica del dominio del servizio migrati differiscono dalla funzionalità originale.

  • Due sistemi hanno una semantica diversa e richiedono lo scambio di dati, ma non è pratico modificare un sistema per renderlo compatibile con l'altro sistema.

  • Desiderate utilizzare un approccio rapido e semplificato per adattare un sistema all'altro con un impatto minimo.

  • L'applicazione comunica con un sistema esterno.

Problemi e considerazioni

  • Dipendenze del team:Quando diversi servizi in un sistema sono di proprietà di team diversi, la nuova semantica del modello di dominio nei servizi migrati può portare a cambiamenti nei sistemi di chiamata. Tuttavia, i team potrebbero non essere in grado di apportare queste modifiche in modo coordinato, perché potrebbero avere altre priorità. L'ACL separa i chiamanti e traduce le chiamate in modo che corrispondano alla semantica dei nuovi servizi, evitando così che i chiamanti debbano apportare modifiche al sistema attuale.

  • Spese generali operative:Il modello ACL richiede uno sforzo aggiuntivo per il funzionamento e la manutenzione. Questo lavoro include l'integrazione dell'ACL con strumenti di monitoraggio e avviso, il processo di rilascio e i processi di integrazione continua e distribuzione continua (CI/CD).

  • Singolo punto di errore:Qualsiasi errore nell'ACL può rendere irraggiungibile il servizio di destinazione, causando problemi alle applicazioni. Per mitigare questo problema, è necessario integrare funzionalità di ripetizione dei tentativi e interruttori automatici. Vedi lariprova con backoffeinterruttoremodelli per comprendere meglio queste opzioni. L'impostazione di avvisi e registri appropriati migliorerà il tempo medio di risoluzione (MTTR).

  • Debito tecnico:Come parte della tua strategia di migrazione o modernizzazione, valuta se l'ACL sarà una soluzione transitoria o provvisoria o una soluzione a lungo termine. Se si tratta di una soluzione provvisoria, è necessario registrare l'ACL come debito tecnico e disattivarlo dopo la migrazione di tutti i chiamanti dipendenti.

  • Latenza:Il livello aggiuntivo può introdurre latenza dovuta alla conversione delle richieste da un'interfaccia all'altra. Si consiglia di definire e testare la tolleranza delle prestazioni nelle applicazioni sensibili ai tempi di risposta prima di implementare ACL negli ambienti di produzione.

  • Collo di bottiglia in scala:Nelle applicazioni ad alto carico in cui i servizi possono essere scalati in base al picco di carico, l'ACL può diventare un collo di bottiglia e causare problemi di scalabilità. Se il servizio di destinazione è scalabile su richiesta, è necessario progettare l'ACL in modo che sia scalabile di conseguenza.

  • Implementazione specifica o condivisa del servizio:È possibile progettare ACL come oggetto condiviso per convertire e reindirizzare le chiamate a più servizi o classi specifiche del servizio. Prendi in considerazione la latenza, la scalabilità e la tolleranza agli errori quando determini il tipo di implementazione per ACL.

Implementazione

Puoi implementare ACL all'interno della tua applicazione monolitica come classe specifica per il servizio da migrare o come servizio indipendente. L'ACL deve essere disattivato dopo la migrazione di tutti i servizi dipendenti nell'architettura dei microservizi.

Architettura di alto livello

Nell'architettura di esempio seguente, un'applicazione monolitica dispone di tre servizi: servizio utente, servizio carrello e servizio account. Il servizio carrello dipende dal servizio utente e l'applicazione utilizza un database relazionale monolitico.

Applicazione monolitica con tre servizi.

Nella seguente architettura, il servizio utente è stato migrato a un nuovo microservizio. Il servizio cart chiama il servizio utente, ma l'implementazione non è più disponibile all'interno del monolite.  È anche probabile che l'interfaccia del servizio appena migrato non corrisponda all'interfaccia precedente, quando si trovava all'interno dell'applicazione monolitica.

Applicazione monolitica in cui un servizio viene trasferito a un microservizio.

Se il servizio carrello deve chiamare direttamente il servizio utente appena migrato, ciò richiederà modifiche al servizio carrello e un test approfondito dell'applicazione monolitica. Ciò può aumentare il rischio di trasformazione e l'interruzione del business. L'obiettivo dovrebbe essere quello di ridurre al minimo le modifiche alla funzionalità esistente dell'applicazione monolitica.

In questo caso, ti consigliamo di introdurre un ACL tra il vecchio servizio utente e il servizio utente appena migrato. L'ACL funziona come un adattatore o una facciata che converte le chiamate nell'interfaccia più recente. L'ACL può essere implementato all'interno dell'applicazione monolitica come classe (ad esempio,UserServiceFacadeoUserServiceAdapter) che è specifico per il servizio che è stato migrato. Il livello anticorruzione deve essere disattivato dopo la migrazione di tutti i servizi dipendenti nell'architettura dei microservizi.

Aggiungere un livello anticorruzione.

Implementazione utilizzandoAWSservizi

Il diagramma seguente mostra come è possibile implementare questo esempio di ACL utilizzandoAWSservizi.

Implementazione del modello ACL conAWSservizi.

Il microservizio utente viene migrato dall'applicazione monolitica ASP.NET e distribuito comeAWS Lambdafunzione su AWS. Le chiamate alla funzione Lambda vengono indirizzate tramiteGateway API Amazon. L'ACL viene implementato nel monolite per tradurre la chiamata per adattarla alla semantica del microservizio utente.

QuandoProgram.cschiama il servizio utenti (UserInMonolith.cs) all'interno del monolite, la chiamata viene indirizzata all'ACL (UserServiceACL.cs). L'ACL traduce la chiamata nella nuova semantica e interfaccia e chiama il microservizio tramite l'endpoint API Gateway. Il chiamante (Program.cs) non è a conoscenza della traduzione e del routing che avvengono nel servizio utenti e nell'ACL. Poiché il chiamante non è a conoscenza delle modifiche al codice, si riducono le interruzioni dell'attività e si riducono i rischi di trasformazione.

Codice di esempio

Il seguente frammento di codice fornisce le modifiche al servizio originale e l'implementazione diUserServiceACL.cs. Quando viene ricevuta una richiesta, il servizio utente originale chiama l'ACL. L'ACL converte l'oggetto di origine in modo che corrisponda all'interfaccia del servizio appena migrato, chiama il servizio e restituisce la risposta al chiamante.

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; } }

GitHubmagazzino

Per un'implementazione completa dell'architettura di esempio per questo modello, vedereGitHubrepository pressohttps://github.com/aws-samples/anti-corruption-layer-pattern.

Contenuti correlati