腐敗防止層パターン - AWS 規範ガイダンス

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

腐敗防止層パターン

Intent

腐敗防止層 (ACL) パターンは、ドメインモデルのセマンティクスをあるシステムから別のシステムに変換する仲介層として機能します。上流チームが確立した通信契約を利用する前に、上流の境界付きコンテキスト (モノリス) のモデルを下流の境界付きコンテキスト (マイクロサービス) に適したモデルに変換します。このパターンは、下流の境界コンテキストにコアサブドメインが含まれている場合や、上流モデルが変更不可能なレガシーシステムである場合に当てはまる可能性があります。また、発信者の通話をターゲットシステムに透過的にリダイレクトする必要がある場合に通話者が変更されるのを防ぐことで、変革のリスクと業務の中断を軽減します。

モチベーション

移行プロセス中に、モノリシックアプリケーションをマイクロサービスに移行すると、新しく移行されたサービスのドメインモデルセマンティクスが変更される可能性があります。モノリス内の機能がこれらのマイクロサービスを呼び出す必要がある場合は、呼び出し元のサービスを変更することなく、呼び出しを移行されたサービスにルーティングする必要があります。ACL パターンを使用すると、モノリスは、呼び出しを新しいセマンティクスに変換するアダプターまたはファサードレイヤーとして機能することで、マイクロサービスを透過的に呼び出すことができます。

適用性

次のような場合にこのパターンを使用することを検討してください。

  • 既存のモノリシックアプリケーションは、マイクロサービスに移行された関数と通信する必要があり、移行されたサービスドメインモデルとセマンティクスは元の機能とは異なります。

  • 2 つのシステムはセマンティクスが異なり、データを交換する必要がありますが、一方のシステムを他方のシステムと互換性があるように変更することは現実的ではありません。

  • 迅速でシンプルなアプローチを使用して、影響を最小限に抑えながら、あるシステムを別のシステムに適応させたいと考えています。

  • アプリケーションは外部システムと通信しています。

問題と考慮事項

  • チームの依存関係:システム内のさまざまなサービスがさまざまなチームによって所有されている場合、移行されたサービスの新しいドメインモデルのセマンティクスにより、呼び出し側のシステムが変更される可能性があります。ただし、チームには他の優先事項がある可能性があるため、これらの変更を協調して行うことができない場合があります。ACL は呼び出し先を切り離し、新しいサービスのセマンティクスに合わせて呼び出しを変換します。これにより、呼び出し元が現在のシステムを変更する必要がなくなります。

  • 運用上のオーバーヘッド:ACL パターンの運用と保守には追加の労力が必要です。この作業には、ACLを監視および警告ツール、リリースプロセス、継続的インテグレーションおよび継続的デリバリー(CI/CD)プロセスと統合することが含まれます。

  • 単一障害点:ACL に障害があると、ターゲットサービスにアクセスできなくなり、アプリケーションの問題が発生する可能性があります。この問題を軽減するには、リトライ機能とサーキットブレーカーを組み込む必要があります。を参照してくださいバックオフして再試行そしてサーキットブレーカーこれらのオプションについてさらに理解を深めるためのパターン。適切なアラートとロギングを設定すると、平均解決時間 (MTTR) が改善されます。

  • 技術的負債:移行またはモダナイゼーション戦略の一環として、ACL が一時的な解決策になるのか、暫定的な解決策になるのか、それとも長期的な解決策になるのかを検討してください。暫定的な解決策であれば、ACL を技術的負債として記録し、依存関係にあるすべての発信者を移行した後に ACL を廃止する必要があります。

  • レイテンシー:レイヤーを追加すると、あるインターフェイスから別のインターフェイスへのリクエストの変換により、レイテンシーが発生する可能性があります。ACL を実稼働環境に展開する前に、応答時間に敏感なアプリケーションのパフォーマンストレランスを定義してテストすることをお勧めします。

  • スケーリングのボトルネック:サービスがピーク負荷までスケーリングできる高負荷アプリケーションでは、ACL がボトルネックになり、スケーリングの問題が発生する可能性があります。ターゲットサービスがオンデマンドでスケーリングする場合は、それに応じてスケーリングするように ACL を設計する必要があります。

  • サービス固有の実装または共有実装:ACL を共有オブジェクトとして設計して、呼び出しを複数のサービスまたはサービス固有のクラスに変換およびリダイレクトできます。ACL の実装タイプを決定する際には、レイテンシー、スケーリング、および耐障害性を考慮してください。

実装

ACL は、移行するサービスに固有のクラスとして、または独立したサービスとしてモノリシックアプリケーション内に実装できます。すべての依存サービスがマイクロサービスアーキテクチャに移行されたら、ACL を廃止する必要があります。

高レベルのアーキテクチャ

次のアーキテクチャ例では、モノリシックアプリケーションには、ユーザーサービス、カートサービス、アカウントサービスの 3 つのサービスがあります。カートサービスはユーザーサービスに依存し、アプリケーションはモノリシックなリレーショナルデータベースを使用します。

3 つのサービスを備えたモノリシックアプリケーション。

次のアーキテクチャでは、ユーザーサービスは新しいマイクロサービスに移行されました。カートサービスはユーザーサービスを呼び出すが、実装はモノリス内では使用できなくなった。 また、新しく移行したサービスのインターフェースが、モノリシックアプリケーション内にあったときの以前のインターフェースと一致しない可能性もあります。

1 つのサービスがマイクロサービスに移行されるモノリシックアプリケーション。

カートサービスが新しく移行したユーザーサービスを直接呼び出す必要がある場合は、カートサービスを変更し、モノリシックアプリケーションを徹底的にテストする必要があります。これにより、変革のリスクが高まり、ビジネスが中断する可能性があります。目標は、モノリシックアプリケーションの既存の機能への変更を最小限に抑えることです。

この場合、古いユーザーサービスと新しく移行したユーザーサービスの間に 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 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://github.com/aws-samples/anti-corruption-layer-pattern

関連情報