反貪汙層模式 - AWS 方案指引

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

反貪汙層模式

意圖

反損毀層 (ACL) 模式可做為中介層,將網域模型語意從一個系統轉譯為另一個系統。它會先將上游邊界內容 (monolith) 的模型轉換為適合下游邊界內容 (microservice) 的模型,再使用上游團隊建立的通訊合約。當下游邊界內容包含核心子網域,或上游模型是無法修改的舊版系統時,此模式可能適用。當來電者的呼叫必須以透明方式重新導向至目標系統時,它還可以防止對來電者進行變更,從而降低轉換風險和業務中斷。

動機

在遷移過程中,當單一應用程式遷移至微服務時,新遷移服務的網域模型語意可能會有變更。當需要整體內的功能來呼叫這些微服務時,呼叫應該路由到遷移的服務,而不需要對呼叫服務進行任何變更。ACL 模式允許整體以透明的方式呼叫微服務,方法是做為轉接器或外觀圖層,將呼叫轉換為較新的語意。

適用性

考慮在下列情況下使用此模式:

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

  • 兩個系統具有不同的語意,需要交換資料,但修改一個系統以與其他系統相容並不實際。

  • 您想要使用快速且簡化的方法,將一個系統調整為另一個系統,並將影響降至最低。

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

問題和考量

  • 團隊相依性:當系統中的不同服務由不同的團隊擁有時,遷移服務中的新網域模型語意可能會導致呼叫系統中的變更。不過,團隊可能無法以協調的方式進行這些變更,因為他們可能有其他優先順序。ACL 會分離受話方,並轉譯呼叫以符合新服務的語意,因此不需要呼叫者在目前的系統中進行變更。

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

  • 單點故障:ACL 中的任何故障都可能導致目標服務無法連線,造成應用程式問題。若要緩解此問題,您應該建置重試功能和斷路器。請參閱使用退避斷路器模式重試,以進一步了解這些選項。設定適當的提醒和記錄將改善平均解決時間 (MTTR)。

  • 技術負債:作為遷移或現代化策略的一部分,請考慮 ACL 是暫時性還是臨時解決方案,還是長期解決方案。如果是臨時解決方案,您應該將 ACL 記錄為技術債務,並在遷移所有相依發起人之後解除委任。

  • 延遲:由於將請求從一個界面轉換到另一個界面,額外的 layer 可能會引入延遲。建議您在將 ACL 部署到生產環境之前,在對回應時間敏感的應用程式中定義和測試效能容錯能力。

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

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

實作

您可以在單體應用程式中實作 ACL,做為要遷移之服務的特定類別,或做為獨立服務。在將所有相依服務遷移至微服務架構之後,必須停用 ACL。

高層級架構

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

具有三個服務的單體應用程式。

在下列架構中,使用者服務已遷移至新的微服務。購物車服務會呼叫使用者服務,但整體內不再提供實作。 當新遷移服務的界面位於單體應用程式內時,它也可能與其先前的界面不相符。

將一個服務移出微服務的單體應用程式。

如果購物車服務必須直接呼叫新遷移的使用者服務,這將需要變更購物車服務,並徹底測試整體應用程式。這可能會增加轉型風險和業務中斷。目標是將整體應用程式的現有功能變更降至最低。

在這種情況下,我們建議您在舊使用者服務和新遷移的使用者服務之間引入 ACL。ACL 可做為轉接器或外觀,將呼叫轉換為較新的界面。ACL 可在單體應用程式內實作為 類別 (例如, UserServiceFacadeUserServiceAdapter),其專屬於已遷移的服務。所有相依服務遷移至微服務架構後,必須停用反貪汙層。

新增反貪汙層。

使用 AWS 服務實作

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

使用 AWS 服務實作 ACL 模式。

使用者微服務會從 ASP.NET 整體應用程式遷移,並在 AWS 上部署為 AWS Lambda函數。Lambda 函數的呼叫會透過 Amazon API Gateway 路由。ACL 部署在整體中,以轉譯呼叫,以適應使用者微服務的語意。

當 在整體內部Program.cs呼叫使用者服務 (UserInMonolith.cs) 時,呼叫會路由到 ACL (UserServiceACL.cs)。ACL 會將呼叫轉譯為新的語意和界面,並透過 API Gateway 端點呼叫微服務。發起人 (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://https://github.com/aws-samples/anti-corruption-layer-pattern

相關內容