AWS Lambdaについて

清水崇之(以下、清水):ではさっそくTECH PLAYさんの抱えている課題、相談についてお話を聞いていきたいと思います。1つ目の相談です。「AWS Lambdaを活用するアーキテクチャとデプロイのベストプラクティスについて教えてください」という質問をいただいています。

今回、AWSについての話をしますが、「AWS Lambdaってそもそも何ですか?」と疑問を持つ方もいるかと思うので、まずはAWS側から、Lambdaについて紹介したいと思います。

福井厚氏(以下、福井):AWS Lambdaについて簡単に紹介したいと思います。AWS Lambdaは、いわゆるサーバーレスのサービスの1つになっていて、Lambdaが実行環境を提供するというサービスです。

具体的に言うと、お客さまが書いたアプリケーションのコードをAWS Lambda上にアップロードすると、指定したタイミングでアップロードしたコードが自動的に実行される実行環境をAWSが提供する、というサービスです。

そのタイミングはいつなんだと言うと、いわゆるイベント駆動アーキテクチャをベースにしていて、さまざまなイベントをきっかけにそのコードが実行されるかたちをとっています。

例えば、ファイルがアップロードされてS3のバケットにファイルが保存されたタイミングや、APIが呼び出されたタイミングです。それぞれ同期や非同期で実行される環境をAWS自身が提供することで、自動的にスケールしたり、あるいはアップデートのパッチを自動的に適応したりをすべてAWS側でやってくれるので、お客さまはコードを書くこと、ビジネスロジックを書くことにだけに集中できるサービスになります。

TECH PLAYでAWS Lambdaを使用したい背景

清水:ありがとうございます。では、さっそくTECH PLAYさんの相談に入っていきたいと思いますが、TECH PLAYさん、いかがですか?

鈴木康広(以下、鈴木):ありがとうございます。(スライドを示して)TECH PLAYは、みなさまが知っているとおり、イベント情報の掲載や、イベント情報の作成ができるサービスです。コンテンツの幅をいろいろ広げていきたい、よりユーザーのみなさまにお役に立てるような情報を、いろいろ集約してお届けしていきたいと考えています。

最近は、企業のテックブログを集約して届けるサービスも提供を始めています。これからいろいろなフォーマットに合わせた情報収集機能を迅速にどんどん作っていきたいなと考えていて、その際には先ほど説明があったようなLambdaの機能が不可欠だなと考えています。

(スライドを示して)今触れたテックブログの集約サービスというものですが、TECH PLAYの中では「ブログ」という名前で提供しています。さまざまな企業がテックブログを提供していますが、許可をいただいた企業に関しては、提供されているRSSを収集してリンクを掲載するサービスを提供しています。

ここは、今は独自で実装したクローラーを使ってRSSを取得しているのですが、実はRSSも提供している会社によってフォーマットが違っていたりするので、個別に作って対応したりもしています。このあたりも、Lambdaに乗せ換えることできっともっとスマートにやれるんじゃないかなと考えています。

テックブログ集約サービスのアーキテクチャの状態と、3つの相談

鈴木:(スライドを示して)これが考えているアーキテクチャです。担当の中村さん、説明(してもらっても)いいですか?

中村航也(以下、中村):はい。では、テックブログ集約サービスの具体的なアーキテクチャと、相談したい内容について、TECH PLAYの中村からお伝えします。

(スライドを示して)こちらの図の記載のとおり、各企業のテックブログが取得できるフィード化を、AWS Lambdaの関数を使ってそれぞれ収集しています。各企業のフィードは先ほどお伝えしたとおり、フォーマットや必要な後処理が異なるため、設定や処理内容が異なる複数のLambda関数に分けて実装しています。

このLambda関数は、AWSのEventBridgeのスケジュール機能によって1日に1回、Lambda関数を使ってRSSフィードからブログを取得する形式で呼び出されています。まだサービスが小規模であったことのなごりで、このLambda関数はブラウザから使えるAWSのコンソールからzip形式でアップロードしています。

ただ最近はサイズ制限をオーバーすることが多くなってきてしまったため、S3を経由してAWS Lambdaにソースコードをアップロードする運用に移り変わっています。また、各Lambda関数はいずれもブログを集約する目的で実装されているため、処理が共通している箇所も数多くありますが、それぞれ別のLambda関数として共通する処理がアップロードされているような状態です。

また、EventBridgeのスケジュール設定も、Lambda関数と同様にコンソールから設定する運用になっています。今後、サービスを拡大して多くの企業のブログを収集するようになっていくと、EventBridgeのスケジュールの設定や、Lambda関数の種類が増加していくことで、デプロイや運用に多大な労力がかかることが懸念されています。

(スライドを示して)そこで、今回はこちらの3点について相談します。

1つ目は、よりよいデプロイ方法があれば知りたいということで、複数のLambda関数をより管理しやすくデプロイする方法があれば教えていただきたいです。

2つ目は、複数のLambda関数間で共通する処理は、どのように実装、デプロイを行うのが最適なのでしょうか。共通する処理をデプロイし、それぞれのLambda関数で再利用する方法があれば教えていただきたいです。

3つ目は、EventBridgeによるスケジューリングが煩雑になってきました。これを解決する方法はあるでしょうか。サービスの拡大にともなって、「EventBridgeにこの関数を使って、このRSSフィードから取得する」といったスケジュールの設定の管理が煩雑になってきたため、同じくこれを解決する方法があれば、教えていただきたいです。

以上、この3点が今回相談したい内容になります。

複数のLambda関数をより管理しやすくデプロイする方法

清水:ありがとうございます。AWSのSAのみなさん、いかがですか。

福井:まず、AWSを使っていただき本当にありがとうございます。

鈴木:こちらこそありがとうございます。いつもお世話になっております。

福井:ありがとうございます。まず1番の相談で、今は過去の経緯からマネジメントコンソールを使って、zipファイルもしくはS3にアップロードしたファイルをデプロイしてもらっているということですが、こちらはやはり手作業によるミスも発生する可能性が高いので、自動化を考えて今後はデプロイしてもらうのがいいかなと思っています。

(スライドを示して)その自動化の第一歩として、コマンドラインで実行できるSAMのCLIというコマンドがあります。これは今スライドに出ているServerless Application Modelというツールというか機能があって、これを使ってもらうことによって、誰がいつデプロイしても同じようにデプロイできて、しかも、ビルドして、S3に置いて、アップロードしてデプロイすることが全部自動で行うことができます。

こういったものを使うことによって、将来的にはいわゆるCI/CDのパイプラインにSAMをCLIに乗せてデプロイすることも、すごくやりやすくなります。

(スライドを示して)SAMの動きとしては、まずSAMのテンプレートを自動生成する「sam init」というコマンドがあります。これはCloudFormationのテンプレートのスーパーセットになっていて、CloudFormationテンプレートと同じですが、より簡単に記述できるような拡張がされています。

このSAMのテンプレートを記述したものに対して、SAMの「build」コマンドを実行すると、自動的にこのSAMがビルドされて、そのあとさらにSAM deployのコマンドを実行することによって、実は内部的にはCloudFormationテンプレートにトランスパイルされて、それが実際にAWSにデプロイされるところまで自動で行われます。

これをやることによって、簡単に言うとSAMをビルドして、SAMをデプロイするコマンドを実行するだけで、毎回デプロイが簡単にでき、それをさらにコマンドラインをパイプラインに乗せることによって、さらにソースコードのアップロードからデプロイまで、全自動で行えるようになるので、ぜひ、このSAMをご利用いただくことをおすすめしたいなと思っています。

清水:TECH PLAYさん、いかがですか。ちょっと若干仕込みっぽくなってしまった雰囲気があるんですが、これはリアルタイムでやり取りしているので、いかがですか。もし、コメントがあれば、いただけないですか。

中村:こちらのSAMを使うことで、例えばLambda関数を実行するためのIAM ロールの管理などに、SAMに移管できますかね。

福井:はい、おっしゃるとおりです。このIAM ロールを指定しても、SAMを利用することによって、より簡単に記述できるようになっているので、そちらもぜひ、ご利用いただければと思います。

中村:ありがとうございます。

福井:ありがとうございます。

複数のLambda関数間で共通する処理の実装・デプロイ方法

福井:では、2番目ですね。こちらも複数のLambda関数間で共通の処理をどのように実装するかというところです。Lambda Layerという機能が提供されていて、Lambda Layersを使ってレイヤーの中に共通の機能をライブラリとして登録してもらうと、そのレイヤーを各Lambdaファンクションが読み込むことができるようになって、共通機能を利用しやすくなります。ぜひ、こちらも検討してもらえればと思います。レイヤーについて何か質問はありますか?

中村:こちらのLambda Layerも先ほどのSAMで管理可能ですか?

福井:はい、そのとおりです。打ち合わせしていなかったのに、本当にいい質問をもらえてありがたいなと思っています。そのとおりで、SAMに対してレイヤーを1行定義するだけで、そのLambda Layerを読み込めるようになっているので、非常に簡単にデプロイすることができます。

清水:福井さん、なにかデメリットみたいなものはないんですか?

福井:デメリットというよりは、zip形式の場合、レイヤーも含めたサイズがzipのアップロードできるサイズになるので、サイズの面は注意が必要です。もしzipのファイルサイズ制限を超えるようであれば、今度はコンテナ形式のイメージのデプロイも検討してもらえればと思います。

清水:ちょうど今、質問が1個入ってきたのですが、SAMと同じようなことがAWS CDKでもできるんじゃないかと。使い分けのポイントなどがあれば教えてほしいという意見があったんですが、いかがですか。

福井:今回のようなサーバーレスの環境だけであれば、SAMでデプロイするのが簡単でいいかなと思うんですが、それ以外のAWSのリソースを含むような環境をIaC(Infrastructure as Code)として管理していきたいのであれば、CDKは非常に良い選択だと思います。

なので、どの範囲を1つの枠として管理するかによって使い分けることは可能なのと、もう1つはSAMとCDKを連携して動作させることもできるようになっているので、SAMでローカルでテストした環境、ローカルでテストした上でCDKでデプロイできるようになっているので、そういった組み合わせも可能になっています。

清水:TECH PLAYさんいかがですか。何かこちらに関して追加の質問などはありますか?

中村:SAMをCloudFormationに変換して、それを稼働するということでしたが、CloudFormationでできることは基本的にSAMでできるという認識でいいでしょうか。

福井:そのとおりです。先ほどSAMはより簡単に記述できるとお話ししましたが、SAMがサポートしていないリソースに対しては、通常のCloudFormationの記述をそのままSAMのテンプレートの中に書けるので、CloudFormationでできることはすべてできると考えてもらってけっこうです。

下川賢介(以下、下川):最初はAWSのマネジメントコンソールを使っていたということで、なぜこれがダメなのかだけ一言言っておきます。なにかトラブルが起きた時に再現性を得るために同じ登録をしようと思っても、画面をどういうふうに自分でポチポチしていたかは記録もされていません。

例えば、他人にその操作を伝えようとしても、言葉で伝えるとかメールで伝えるのは(難しく)、それで本当に正確に再現できる環境が得られるかと言うと、なかなか難しいんじゃないのかなと思っていて。

そこでInfrastructure as Codeみたいな考え方が出てきます。補足としては、その1つがCloudFormationであり、CDKであり、今日紹介したSAMなのかなというところです。

中村:ありがとうございます。

煩雑になったEventBridgeによるスケジューリングの解消方法

清水:では3つ目の質問にも行きましょうか。

福井:質問いただいたように、EventBridgeで時間を指定して何かタスクを実行させることはもちろんできますが、スケジューリングが複雑になってきた理由はそもそもどういったものなんでしょうか。

中村:スケジューリングが複雑になってきた理由しては、テックブログを取得するもとのRSSフィード1件に対してそれぞれスケジュールを切って作っているので、RSSフィードの数が増えていけば増えていくほど、スケジュールの数も多くなっていきました。

それぞれのフィードに対応するLambda関数はこれで、これを使って、ここに取りに行くという(感じで)スケジュールがずらっと並ぶ状態になっているので、かなり煩雑になってしまっています。

福井:それは、RSSフィードが増えたとしても例えば1日1回取りに行けばいいのか、それともRSSフィードごとに時間指定しないといけないのかというと、どちらでしょうか。

中村:それぞれ各フィードに対して1日1回取得しに行くのが望ましいです。

福井:それで構わないということなんですよね。

中村:はい。

福井:ということであれば、1つの解決策としてはFanoutパターンが考えられます。具体的に言うと、SNSとSQSを使ってもらって、SNSに対して1日1回トピックを送信する。

例えば、EventBridgeで時間指定して送信します。そのトピックに入ったものを、各RSSフィードにSQSを立ててもらって、それらがそのトピックに対してメッセージを送信するようにサブスクライブしていくというかたちをとります。

(スライドを示して)そうすると、1つのタイミングによってすべてが並列的に各キューでメッセージが送信されて、その先のLambdaファンクションが実際にRSSフィードを取りに行くかたちにすれば、イベントとしては1個のイベントで全部を取ることができます。

(スライドを示して)今出ているようなかたちのFanoutパターンが1つ使えるかなと思います。こちらはどうでしょうか。

中村:確かにそうですね。こちらの構成のほうが非常にシンプルだし、SQSに入れるということは、例えばいくつかのRSSフィードは同じドメインで書いてあるものがあって、今言ってもらいましたが、そのドメインでは短時間で大量のアクセスを行いたくないという要件があった場合は、SQSに1個ずつ入れていって1個ずつ処理していけば、その問題は解決可能でしょうか。

福井:そうですね。メッセージの処理数は指定できるので、一度に1メッセージの処理も可能です。こういった方法もあるし、例えばStep Functionsというワークフローのサービスを使って、ある条件で分岐して並列に実行したり、それをまた待ち受けたりをワークフローとして処理する方法も別にありますね。

下川:私はこの話を聞いた時に、Step Functionsがけっこう合いそうだなと思いました。EventBridgeでスケジューリングして、1日1回EventBridgeからStep Functionsを起こすようにしておいて、Step Functionsまで行けば、先ほど言ったみたいに送信先、RSSの取得先はたくさんあると思いますが、それを並列でStep Functionsを使って取得できるので、AサイトからのRSS、BサイトからのRSSを並列で並行して取得することがしやすいんじゃないのかなと思いました。

福井:Step Functionsの中には、配列を渡したら配列分だけ並列に処理する機能があるので、RSSフィードが増えた場合に、その配列を増やしてもらうだけで、ワークフロー自体を変えなくてもいいというやり方もできるようになっていますね。

下川:そうですね。EventBridgeがその配列を伝えるというよりは、なにかDynamoDBとか。

福井:そうですね。そこに(入れる)。

下川:RDSみたいなデータベースに配列の要素を入れておいて、それをStep Functionsの中でワークフローの中で手続きとして取ってきて、(そうすると)それが配列になるので、それを並列実行させるのが、このビジネスロジックだと合うんじゃないのかなという気はしますね。

福井:そうですね。どちらにしてもメッセージを挟んだり、イベントを挟むことによって並列処理を行ったり。あるいは、タイマーの数を減らすことができたりするかなと思います。

このFanoutのパターンの場合はキューを挟んでいるので、例えばLambdaファンクションが実行に失敗したとしてもメッセージが戻るので、再実行できたり。そういう意味で、信頼性や可用性の向上も見られるかなと思います。