サーバーレスアーキテクチャのSimple is not Easy
はじめに
おはようございます、加藤です。この記事はAWS Lambda と Serverless Advent Calendar 2023シリーズ1、5日目の記事です。
この記事の主張はサーバーレスアーキテクチャで開発している場合において、ある機能を実装する際にソフトウェアだけで解決することはEasyだが、アーキテクチャで解決した方がSimpleであるということです。ただし、SimpleがEasyより常に優れている、選択すべきということではありません。自分たちのコンテキストに応じてSimpleかEasyを選択することが必要です。
ケーススタディ
レスポンスに時間がかかるWebAPI
WebAPIをAWS上でサーバーレスアーキテクチャで構築する場合にはAPI GatewayとLambdaが良く使われます。あるエンドポイントが外部のAPIを呼び出しておりそのレスポンスに25秒かかるとします。
API Gatewayの最大タイムアウトは29秒なので同期処理としてギリギリ実装することができます。
これは簡単に実装ができますが、①外部APIのレスポンス時間に揺れがありタイムアウトを超過してしまい動作が不安定になる ②追加で外部APIを呼び出す必要が出てきてタイムアウトを超過してしまうという問題があります。
Easy pattern
クライアントから受け取ったリクエストをSQSに投入し処理を完了した後に、そのSQSをトリガーに実行されるLambdaで外部APIを呼び出すことで時間制限から解放されます。
ですが、この場合はレスポンスを保存する必要があります。そして、クライアントは取得のAPI呼び出しを別途行う必要があります。初回のリクエスト後にユーザーアクション無しに結果を伝える必要があるならばクライアントはポーリングする必要があるでしょう。
Simple pattern
後者をSimpleとすることに異議を持つ方も多いと思います。ですが、ソフトウェアとアーキテクチャ両方を考慮すると後者がSimpleだと私は考えています。
AWSリソースの数は増えていますが、その分以上にソフトウェアがSimpleになっています。Simple patternでは3つのLambdaが登場しますが、①リクエストをSQSに送信する ②外部APIを呼び出し結果を保存する ③DynamoDBから結果を取得しレスポンスすると単一の関心毎だけを処理しています。
私はこの場合、Simple patternを選択します。ですが、Simple patternを選択することが常に正しいというわけではありません。開発チームにソフトウェア開発のノウハウはあるが、API Gateway+LambdaでのWebAPI開発の知識か相談先がないならばEasy patternを選択し単一のLambda関数内でハンドリングを頑張った方が良いです。
Simple patternにおいてCreateとReadのLambdaで同じソフトウェア上のモデルを共有する必要がある場合は、
AWS Lambdaのデプロイパッケージをどの範囲で構築すべきか が参考になります。
AWS Step Functionsから呼び出すLambdaの粒度
あとで追記します
Easyへの誘惑
サーバーレスに慣れている方は、ケーススタディで紹介された例を見てなんの変哲の無い、典型的なサーバーレスアーキテクチャのパターンだと思われたのではないでしょうか。実際その通りです。
ゼロから新規開発している時に、最初から要件が出そろっていればSimpleパターンを発見することはそこまで難易度が高いことではありません。問題はリリース後、継続的にソフトウェアを開発している際に、要件が追加・変更された場合です。
この際に、どうしてもソフトウェアだけで解決しようとする誘惑に駆られます。場合によっては誘惑に駆られていることを自覚すらできず比較せずにEasy patternを選択してしまうこともあります。
さらに、深掘りすると追加された要件だけを注視してしまっていて、既存の要件と追加要件を合算して検討すれば発見できたもっと良いアーキテクチャを見逃してしまうこともあります。(私はよくやらかします)
あとがき
最近、よく直面する問題でいくらでも書けるだろうと見切り発車したら思い出せない、良い感じの例にできず中途半端なブログになってしまいました。すみません。
Discussion