TECH BLOG
AWSを使った疎結合なサービスの作り方
こんにちは、IGD/SGUに所属するソリューションエンジニアの森です。業務ではAWSを活用し、ドローン関連サービスやAI基盤のインフラアーキテクチャ設計・開発を担当しています。
アーキテクチャ設計のレビューを受ける際、「疎結合」という言葉を頻繁に耳にしました。ソフトウェア設計においても「疎結合」と「密結合」という概念はありますが、インフラアーキテクチャでは具体的に何をもって疎結合とするのか、どのような構成がそれに当たるのか、密結合との違いは何なのかといった点に興味を持ちました。本記事では、それらを整理しながら、自身も疎結合な構成を適切に考えられるようになることを目的として執筆しました。
インフラアーキテクチャにおける疎結合/密結合
「疎結合」とは、システムの各コンポーネントが互いに依存を最小限に抑えた設計のことを指します。一方、「密結合」はコンポーネント同士が強く依存している設計を指します。AWSが提供するベストプラクティス集であるWell Architected Frameworkでは疎結合、密結合について以下のように触れられています。
密結合のシステムでは、あるコンポーネントを変更すると、そのコンポーネントに依存する他のコンポーネントも変更しなければならなくなり、結果として、すべてのコンポーネントのパフォーマンスが低下する可能性があります。疎結合はこの依存関係を壊すため、依存コンポーネントが知る必要があるのは、バージョン管理されて公開されたインターフェイスのみです。依存関係があるコンポーネント間に疎結合を実装すると、あるコンポーネントの障害が別のコンポーネントに影響を及ぼさないように隔離することができます。
疎結合では、コードの変更やコンポーネントへの機能の追加を自由にできる一方で、そのコンポーネントに依存する他のコンポーネントへのリスクを最小限に抑えることができます。また、回復力を細分化でき、コンポーネントレベルでスケールアウトしたり、依存関係の根本的な実装さえも変更したりできます。
引用)REL04-BP02 疎結合の依存関係を実装する - AWS Well-Architected フレームワーク
この考え方をわかりやすくするため、LEGOブロックを使った例えで説明してみます。例えば、ある形を一つひとつのブロックを組み立てて作る場合を「疎結合」、既に完成した形のパーツをそのまま利用する場合を「密結合」と考えることができます。
ブロックを組み立てる場合は、LEGOの規格に沿っている限り色やサイズの変更が容易で、破損してもそのパーツのみを交換すれば済むため影響範囲が小さくなります。一方で、完成品のパーツを使う場合は作業コストは低いものの、色やサイズの変更が難しく、破損時にはパーツ全体を交換する必要があるため影響が大きくなります。
図1. LEGOブロックを使った疎結合/密結合の例左が疎結合、右が密結合
このように疎結合なシステムには
-
障害の影響を局所化できる
-
柔軟な変更や機能拡張が可能
-
独立したコンポーネントごとにスケールアウト
といった利点があります。この柔軟性は、サービスを長期的に運用しながら成長させる上で非常に重要なポイントになります。
AWSで作る疎結合なシステム
疎結合なシステムを作るには
LEGOブロックでの例えのように、疎結合なシステムを作るには機能や役割ごとに分離されたシステム同士をつなぎ合わせて一つのサービスを構築する必要があります。この分離されたシステム間で通信するための「つなぎ目」には主に
-
API
-
メッセージキュー
-
pub/sub
-
イベントバス
が採用されます。各つなぎ目の説明とユースケースは以下の通りです。
つなぎ目 |
説明 |
ユースケース |
---|---|---|
API (Application Programming Interface) |
定義されてたI/F仕様に従って各サービスとやりとりを行う。RESTやGraphQL、gRPCなどがよく使用される。 |
マイクロサービス間のデータ取得や操作を行う場合。 例)ユーザー管理サービスと注文管理サービスが、ユーザー情報や注文情報をAPI経由でやり取りする。 |
メッセージキュー |
キューにメッセージを送信し、別のコンポーネントが非同期でそれを受信する。 |
処理時間がかかるタスクを非同期で実行する場合。例)画像アップロード後にバックグラウンドでサムネイルを生成。 |
Pub/Sub (Publish/Subscribe) |
送信者(パブリッシャー)がメッセージをトピックに送信し、購読者(サブスクライバー)がそのトピックを購読してメッセージを受け取る。 |
複数のシステムに同時に通知を送信する場合。例)商品が購入された際、在庫管理サービス、請求サービス、通知サービスが購読し、それぞれに応じた処理を実行。 |
イベントバス |
複数のコンポーネント間でイベントを中心に通信を行う仕組み。特定のコンポーネントが発行したイベントがバスを介して他のコンポーネントに配信される。 |
システム全体でのイベント駆動型アーキテクチャを構築したい場合。 例)ECサイトでユーザーが注文を行うと、イベントバスがそのイベントを各関連サービス(発送、請求、通知)に配信して処理。 |
アプリケーション統合関連サービス
システム間のつなぎ目として働くサービスをAWSでは「アプリケーション統合関連サービス」として提供しており、以下のサービスが該当します。
-
API
-
API Gateway(Amazon API Gateway)
-
-
メッセージキュー
-
SQS(Amazon SQS)
-
-
pub/sub
-
SNS(Amazon SNS)
-
-
イベントバス
-
Amazon CloudWatch Events
-
AWS Step Functions
-
次は実際にこれらのサービスを使った疎結合なシステムの構築例を紹介したいと思います。
AWSで構築する疎結合なシステム例
ここではSQSを使った疎結合なシステムの構築方法とその利点を説明します。私が携わった案件ではSQSとSagemakerを使ってAI解析基盤を構築したため、今回もSagemakerを使った例で説明していこうと思います。
密結合な設計例
※この例はセキュリティリスクもあるので非推奨な構成となります
クライアントはSagemakerの推論エンドポイントに直接リクエストを送ります。シンプルな構成のため開発コストは低いですが、この構成の場合、以下の課題が発生します。
観点 |
課題 |
---|---|
柔軟性の欠如 |
SageMakerのエンドポイント仕様に直接依存するため、仕様変更があった際はSagemakerと接続しているすべてのクライアントアプリケーションを修正する必要がある。 |
リクエストの信頼性 |
SageMakerでエラーや障害が発生した場合、リクエストのリトライや再送の仕組みをクライアント側で実装する必要がある。 |
これらの課題を疎結合な設計にすることで解消していきます。
疎結合な設計例(同期)
リアルタイム性が問われるため同期的に処理を行いたい場合の構成は以下のようになります。
処理の流れは以下のようになります。
-
クライアントはAPI Gatewayに推論リクエストを送る
-
API GatewayからLambdaが呼ばれSagemakerの推論エンドポイントが叩かれる
-
Sagemakerは推論が終わったら結果を返す
密結合の場合に比べてクライアントとSagemakerの間にAPI GatewayとLambdaが追加されています。クライアントはSagemakerに直接アクセスせず、API Gatewayにリクエストを送り結果を受け取ります。この構成により、密結合の場合に発生した課題は以下のように解消できます。
観点 |
課題の解消方法 |
---|---|
柔軟性の欠如 |
LambdaがSagemakerとやりとりをしているため、仕様変更時の影響が各コンポーネントへ及ばず、最小限に抑えることができる |
リクエストの信頼性 |
Lambdaにはリトライ処理を実装する方法があるため、各クライアントでリクエストのリトライや再送の仕組みを実装する必要なく信頼性を保つことができる |
同期的な構成の場合、重いデータの解析やリクエスト数が急激に増えた際にレスポンスタイムが遅くなるといった面もあるため、リアルタイム性が問われない場面であれば次の非同期の場合の疎結合な構成例を採用する方法もあります。
疎結合な設計例(非同期)
非同期的に処理したい場合、構成は以下のようになります。
処理の流れは以下のようになります。
-
クライアントはAPI Gatewayに推論リクエストを送る
-
API GatewayからLambdaが呼ばれ、LambdaはSQSに推論依頼のメッセージを送信し、クライアントに推論依頼完了レスポンスを返す
-
SQSに送られたメッセージを後続のLambdaが受け取り、それをもとにSagemakerへの推論リクエストを実施
-
Sagemakerは推論処理を行い、結果をS3に格納する
-
クライアントは推論結果をS3から閲覧することができる
SQSを使ったことで非同期処理の構成となり、ユーザーは推論の完了を待たず他の操作が行えるようになったため、重いデータの解析や急激なリクエスト増加によるレスポンスタイムの遅延の影響を受けません。
密結合時に発生した課題は以下のように解消されます。
観点 |
課題の解消方法 |
---|---|
柔軟性の欠如 |
LambdaがSagemakerとやりとりをしているため、仕様変更時の影響が各コンポーネントへ及ばず、最小限に抑えることができる |
リクエストの信頼性 |
SQSはリクエストを一時的に保存し、リトライや再送が可能なためリトライや再送の仕組みを各クライアントで持つ必要がない。 (SQSはデッドレターキューをサポートしており、処理が正常に終わらなかったメッセージのデバッグに役立つ。デッドレターキューから通常のメッセージに移動することも可能。Amazon SQS でのデッドレターキューの使用 - Amazon Simple Queue Service ) |
疎結合なシステムの注意点
疎結合なシステムの場合、多くのコンポーネントが連結しているため密結合なシステムに比べて処理速度のパフォーマンスが低下する可能性があります。
今回の例、特にSQSを使った非同期な構成例ではLambdaとSQSを介してSageMakerにリクエストを送信しています。これらの呼び出し時間のラグによりパフォーマンスの低下が発生する可能性があるため、性能試験を行いレスポンスタイムが非機能要件で定めた時間内に収まるかどうかを確認する必要があります。
また、密結合の場合に比べて疎結合なシステムは構成が複雑になるといった面もあるため、開発コストとスケジュールも踏まえたうえでどの設計が最も適しているのかを考える必要があります。
まとめ
本記事では、疎結合と密結合の違いを紹介し、実際にAWSのサービスを使って各構成のメリット/デメリットを解説しました。密結合の場合に比べて疎結合なアーキテクチャの設計は柔軟性と耐障害性に優れており、変更に強く運用もやりやすい一方、構成が複雑になるためパフォーマンスの低下や開発コストの増加といったデメリットもあります。
必ずしも疎結合な構成を選択するのではなく、非機能要件や開発コストといった面をしっかりと定めたうえで適した設計をすることが大切になるなと案件を通じて学ぶことができました。