翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
破損防止レイヤーパターン
Intent
破損防止レイヤー (ACL) パターンは、ドメインモデルのセマンティクスをあるシステムから別のシステムに変換する仲介レイヤーとして機能します。アップストリームの境界コンテキスト (モノリス) のモデルを、アップストリームチームによって確立された通信契約を消費する前に、ダウンストリームの境界コンテキスト (マイクロサービス) に適したモデルに変換します。このパターンは、ダウンストリームの境界コンテキストにコアサブドメインが含まれている場合、またはアップストリームモデルが変更不可能なレガシーシステムである場合に適用できます。また、呼び出しをターゲットシステムに透過的にリダイレクトする必要がある場合に発信者への変更を防ぐことで、変換リスクとビジネスの中断を軽減します。
導入する理由
移行プロセス中に、モノリシックアプリケーションをマイクロサービスに移行すると、新しく移行されたサービスのドメインモデルセマンティクスが変更される可能性があります。これらのマイクロサービスを呼び出すためにモノリス内の機能が必要な場合、呼び出し元のサービスを変更することなく、呼び出しを移行したサービスにルーティングする必要があります。ACL パターンを使用すると、モノリスは、呼び出しを新しいセマンティクスに変換するアダプターまたはファサードレイヤーとして機能することで、マイクロサービスを透過的に呼び出すことができます。
適用対象
次の場合は、このパターンの使用を検討してください。
-
既存のモノリシックアプリケーションは、マイクロサービスに移行された関数と通信する必要があり、移行されたサービスドメインモデルとセマンティクスは元の機能とは異なります。
-
2 つのシステムには異なるセマンティクスがあり、データを交換する必要がありますが、一方のシステムを他のシステムと互換性があるように変更することは実用的ではありません。
-
迅速かつシンプルなアプローチを使用して、影響を最小限に抑えながら、あるシステムを別のシステムに適応させたいと考えています。
-
アプリケーションが外部システムと通信しています。
問題点と考慮事項
-
チームの依存関係: システム内のさまざまなサービスが異なるチームによって所有されている場合、移行されたサービスの新しいドメインモデルセマンティクスは、呼び出し元のシステムの変更につながる可能性があります。ただし、チームは他の優先順位を持っている可能性があるため、調整された方法でこれらの変更を行うことができない場合があります。ACL は発信者を分離し、呼び出しを新しいサービスのセマンティクスに合わせて変換するため、発信者が現在のシステムに変更を加える必要がなくなります。
-
運用上のオーバーヘッド: ACL パターンでは、運用と保守のために追加の労力が必要です。この作業には、ACL をモニタリングおよびアラートツール、リリースプロセス、継続的インテグレーションおよび継続的デリバリー (CI/CD) プロセスと統合することが含まれます。
-
単一障害点: ACL で障害が発生すると、ターゲットサービスに到達できず、アプリケーションの問題が発生する可能性があります。この問題を軽減するには、再試行機能とサーキットブレーカーを構築する必要があります。これらのオプションの詳細については、「バックオフとサーキットブレーカーパターンによる再試行」を参照してください。 サーキットブレーカーパターン適切なアラートとログ記録を設定すると、平均解決時間 (MTTR) が向上します。
-
技術的負債: 移行またはモダナイゼーション戦略の一環として、ACL が一時的または暫定的なソリューションか、長期的なソリューションかを検討してください。暫定的な解決策の場合は、ACL を技術的負債として記録し、すべての依存する発信者が移行された後に廃止する必要があります。
-
レイテンシー: 追加のレイヤーでは、あるインターフェイスから別のインターフェイスへのリクエストの変換によりレイテンシーが発生する可能性があります。ACL を実稼働環境にデプロイする前に、応答時間の影響が厳しいアプリケーションでパフォーマンスの許容値を定義してテストすることをお勧めします。
-
スケーリングのボトルネック: サービスがピーク負荷にスケールできる高負荷のアプリケーションでは、ACL がボトルネックになり、スケーリングの問題が発生する可能性があります。ターゲットサービスがオンデマンドでスケールする場合は、それに応じてスケールするように ACL を設計する必要があります。
-
サービス固有の実装または共有実装: ACL を共有オブジェクトとして設計して、呼び出しを複数のサービスまたはサービス固有のクラスに変換およびリダイレクトできます。ACL の実装タイプを決定するときは、レイテンシー、スケーリング、障害耐性を考慮してください。
実装
ACL は、モノリシックアプリケーション内に、移行するサービスに固有のクラスとして、または独立したサービスとして実装できます。ACL は、すべての依存サービスがマイクロサービスアーキテクチャに移行された後に廃止する必要があります。
高レベルのアーキテクチャ
次のアーキテクチャ例では、モノリシックアプリケーションには、ユーザーサービス、カートサービス、アカウントサービスの 3 つのサービスがあります。カートサービスはユーザーサービスに依存し、アプリケーションはモノリシックリレーショナルデータベースを使用します。

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

カートサービスが新しく移行されたユーザーサービスを直接呼び出す必要がある場合は、カートサービスの変更とモノリシックアプリケーションの徹底的なテストが必要になります。これにより、トランスフォーメーションリスクとビジネスの中断が増加する可能性があります。目標は、モノリシックアプリケーションの既存の機能への変更を最小限に抑えることです。
この場合、古いユーザーサービスと新しく移行されたユーザーサービスの間に ACL を導入することをお勧めします。ACL は、呼び出しを新しいインターフェイスに変換するアダプターまたはファサードとして機能します。ACL は、モノリシックアプリケーション内で、移行されたサービスに固有のクラス ( UserServiceFacade
や などUserServiceAdapter
) として実装できます。すべての依存サービスがマイクロサービスアーキテクチャに移行されたら、破損防止レイヤーを廃止する必要があります。

AWS サービスを使用した実装
次の図は、 サービスを使用して AWS この ACL の例を実装する方法を示しています。

ユーザーマイクロサービスは ASP.NET モノリシックアプリケーションから移行され、AWS に AWS Lambda
がモノリス内でユーザーサービス (UserInMonolith.cs
) をProgram.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 リポジトリ
このパターンのサンプルアーキテクチャの完全な実装については、https://github.com/aws-samples/anti-corruption-layer-pattern