防腐圖層模式 - AWS 規範指引

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

防腐圖層模式

意圖

反損毀層 (ACL) 模式充當中介層,可將網域模型語意從一個系統轉換為另一個系統。它會在使用上游小組建立的通訊合約之前,將上游有界前後關聯 (巨型) 的模型轉譯成適合下游界定前後關聯 (微服務) 的模型。當下游限制前後關聯包含核心子網域,或上游模型是不可修改的舊系統時,此模式可能適用。當呼叫者必須透明地重新導向至目標系統時,它還可以防止對來電者進行變更,從而降低轉型風險和業務中斷。

动机

在移轉程序期間,將整合式應用程式移轉至微服務時,新移轉服務的網域模型語意可能會有所變更。當需要整體式中的功能來呼叫這些微服務時,呼叫應路由至移轉的服務,而不需要變更通話服務。ACL 模式允許整體通過充當適配器或將調用轉換為新語義的外觀層來透明地調用微服務。

適用性

考慮在以下情況下使用此模式

  • 您現有的整合式應用程式必須與已移轉至微服務的函數進行通訊,而移轉的服務網域模型和語意與原始功能不同。

  • 兩個系統具有不同的語義,需要交換數據,但是修改一個系統以與另一個系統兼容是不切實際的。

  • 您想要使用快速簡化的方法,將一個系統調整到另一個系統,而且影響最小。

  • 您的應用程式正在與外部系統通訊。

問題和考慮因素

  • 團隊依賴關係:當系統中的不同服務由不同的團隊擁有時,遷移服務中的新網域模型語意可能會導致呼叫系統的變更。但是,團隊可能無法以協調的方式進行這些變更,因為他們可能有其他優先順序。ACL 將被呼叫者分離並轉換呼叫以符合新服務的語義,從而避免了呼叫者在當前系統中進行更改的需要。

  • 營運開銷:ACL 模式需要額外的努力來操作和維護。這項工作包括整合 ACL 與監控和警示工具、發行程序,以及持續整合和持續交付 (CI/CD) 程序。

  • 單點故障:ACL 中的任何失敗都可能導致目標服務無法連線,進而導致應用程式發生問題。為了緩解此問題,您應該建立重試功能和斷路器。請參閱「」使用輪詢重試断路器模式以了解更多有關這些選項的信息。設定適當的警示和記錄可縮短平均解決時間 (MTTR)。

  • 技術債務:作為移轉或現代化策略的一部分,請考慮 ACL 是暫時性或暫時解決方案,還是長期解決方案。如果這是臨時解決方案,則應將 ACL 記錄為技術債務,並在所有相依呼叫者移轉後將其解除委任。

  • 延遲:由於請求從一個接口轉換到另一個接口,附加層可能會引入延遲。建議您在將 ACL 部署至生產環境之前,先在對回應時間敏感的應用程式中定義並測試效能容忍度。

  • 擴展瓶頸:在服務可擴展到尖峰負載的高負載應用程式中,ACL 可能會成為瓶頸,並可能導致擴展問題。如果目標服務隨需調整,您應該設計 ACL 以相應地擴展。

  • 服務特定或共享實施:您可以將 ACL 設計為共用物件,將呼叫轉換並重新導向至多個服務或服務特定類別。決定 ACL 的實作類型時,請將延遲、擴展和容錯納入考量。

實作

您可以在整合式應用程式中實作 ACL,做為要移轉之服務專屬的類別,或是做為獨立服務。ACL 必須在所有相依服務移轉至微服務架構之後解除委任。

高階架構

在下列範例架構中,整合式應用程式具有三種服務:使用者服務、購物車服務和帳戶服務。購物車服務取決於使用者服務,而應用程式會使用整合式關聯式資料庫。

具有三種服務的單一應用程序。

在下列架構中,使用者服務已移轉至新的微服務。購物車服務會呼叫使用者服務,但實作不再可用於整體式。 新遷移的服務的界面也可能與之前的接口不匹配,當它位於整體應用程序中時。

單片應用程序,其中一個服務被移出到微服務。

如果購物車服務必須直接呼叫新移轉的使用者服務,則需要變更購物車服務,並對整合式應用程式進行徹底測試。這可能會增加轉型風險和業務中斷。目標應該是盡量減少對整體應用程序的現有功能的更改。

在此情況下,建議您在舊使用者服務與新移轉的使用者服務之間引入 ACL。ACL 可作為轉換器或將呼叫轉換為較新介面的外觀。ACL 可以在整體應用程式內部實作為類別 (例如,UserServiceFacade或者UserServiceAdapter) 的特定於已移轉的服務。反損毀層必須在所有相依服務移轉至微服務架構之後解除委任。

添加一個反腐敗層。

實作使用AWS服務

下圖顯示如何使用實作此 ACL 範例AWS服務。

使用實作 ACL 模式AWS服務。

使用者微服務會移轉出 ASP.NET 整合式應用程式,並部署為AWS LambdaAWS 上的功能。對 Lambda 函數的呼叫會透過路由傳送亞馬遜 API 網關。ACL 部署在整體式中,以轉譯呼叫以適應使用者微服務的語義。

何時Program.cs呼叫使用者服務 (UserInMonolith.cs)在整體內部,呼叫被路由到 ACL(UserServiceACL.cs). ACL 會將呼叫轉譯為新的語意和介面,並透過 API 閘道端點呼叫微服務。呼叫者(Program.cs) 不知道使用者服務和 ACL 中發生的翻譯和路由。由於呼叫者不知道程式碼變更,所以業務中斷較少,並降低轉換風險。

範本程式碼

下面的代碼片段提供了對原始服務的更改和實現UserServiceACL.cs。收到請求時,原始使用者服務會呼叫 ACL。ACL 會將來源物件轉換為符合新移轉服務的介面、呼叫服務,然後將回應傳回給呼叫者。

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

GitHub儲存庫

如需此模式範例架構的完整實作,請參閱GitHub儲存庫位於https://github.com/aws-samples/anti-corruption-layer-pattern

相關內容