こんにちは。てぃろです。
今回はAWSでサーバーレスアプリをもっとうまく開発したい!という方に向けて、Lambdaの一歩進んだ使い方や特徴について書きたいと思います。
AWS Lambdaは、Function as a Serviceとして有名で、サーバーレスの代名詞と言っていいサービスです。最近になってまたどんどん機能が追加されて使い勝手がよくなっています。
そんなLambdaについて、re:Invent 2020のセッションであるIncreasing innovation with serverless applicationsの内容を引用しながら、一歩進んだ使い方や特徴などを考察していきたいと思います。
なお、本記事はセッション内容や登場する各種サービスをすべて解説するものではないことをご了承ください。
Lambdaの並列実行とトリガーの関係性
上図は、各トリガーからどんな風にLambdaが実行されているのかその並列性を示しています。
SNS/APIとQueueの場合1トリガーに対して1つLambdaが実行されています。
(雷マークが1トリガー)ですが、Streamの場合だけ1つのLambdaが複数のトリガーの値を受け取ることができるのが特徴です。
Lambdaは同時実行数の上限がありますので、1つのLambda実行の中で複数の値を処理できるということは、同時実行数の上限に引っかかりにくく、実行が失敗しにくいのです。
ただし、Lambdaは実行時間が15分という上限もあるので、あまり多くの処理を任せられないということも注意が必要です。時間に余裕をもって処理が終わるような設計にしておくことが望ましいでしょう。
LambdaのリトライとDead Letter Queue
Lambdaには同期的実行と非同期的実行の2種類の実行方法があります。
注目すべきは非同期的実行のほうで、デフォルトでリトライが設定されているのです。StreamやSQSで実行されるときにも、サービスによりますがリトライが設定されていることがあります!
Lambdaはアーキテクチャを疎結合にできる優れたサービスですが、リトライがあったとしても、エラーやそのフォローが難しいのも事実です。
そんなLambdaにも、Dead Letter Queueがあるんですね!
つまり、Lambdaでも失敗した事実を残しておくことができ、それを検知して処理のさらなるリトライや障害調査への利用が考えられるということです。
そうして、Dead Letter Queueに入ってもよしなに自動復旧してくれればいいですが、そういうわけにもいかないので人への通知も作りこまないといけないですね。
Parameter Storeをうまくつかって、コードとパラメータを分離したい
Lambdaでよく問題になるのが秘密情報の保存場所です。
Lambdaでアクセストークンなどを持っておいてREST APIを実行するなどよくあるケースです。
それに対して、よく使われる方法は環境変数だと思いますが、それでも設定ファイルとして括りだせてもリポジトリに同梱するか、CI/CDパイプラインの設定値に入れておくなどあまり安全性が高い方法とは言えないものが多いです。
そこで、AWS Secrets Managerを使うのがよいのです。
AWS Secrets Managerを使うと上記の例のように、多少コードは増えますが、環境変数から取得するように秘密情報を安全に取得することができます。
Lambdaのストレージは3種類。一時ファイルも作れますよ
MemoryはRAMのことです。Lambdaの設定によってメモリ容量としてその大きさを決めることができます。一般にメモリ容量を大きくするほど起動が遅くなると聞いたことがあります。コールドスタート対策としてアーキテクチャが刷新されるなどしていますので、今はどうなっているかちょっとわからないですが。
/tmp は、ファイルストレージです。自分でファイルを生成して保存することができます。中間ファイルとして一時的に置いておくこともできますが、Lambdaの実行終了後に消えます。
成果物として作った場合には、当然ここからS3に配置するなども可能です。Lambdaをどんなサイズで起動しても一律512MB割り当てられます。
Deployment packageはその名前の通り、実行コードをデプロイする領域です。通常、あまり意識することはないですが、例えば機械学習用などの大きなパッケージになっていた場合250MBを超えることがあるので、そのときにはデプロイできないこともあります。
LambdaはEFSも使えます
EFSとは、Elastic File Systemのことでクラウドネイティブな共有ファイルストレージです。S3とは違ってファイルシステムとして仮想マシンにマウントすることができます。
/tmp でファイルを作った後S3に転送する必要がある場合、AWS SDKを使ってS3への転送コマンドをコーディングする手間や、S3はインターネット越しなので転送が遅いなどの課題があります。
EFSを使えば、ファイルはOSコマンドでコピーすればいいだけになるのでインターネット越しに転送するより早いし、コード量も減らせます。
Lambdaをミニバッチとして使う場合にはありがたい機能です。
Lambdaの同時実行性を制御しよう
Lambdaには同時実行数が存在しており、その上限はリージョンによって異なります。ちなみに、東京リージョンでは1000です。
同時実行数を超えてLambdaは起動できませんので、並列実行性が高くピークだけでもトランザクションが多いアプリケーションでは注意が必要な上限値になってきます。
そこで使える設定は、Provisioned Concurrencyという設定です。
これはそのLambda関数の同時実行数を設定数分確保するというもので、内部的にはLambdaを設定値の数だけ常時起動するもののようです。
つまり、合わせてコールドスタート対策にもなる設定値です。
ただ、この設定さえすればOKというものではなく、アプリケーション特性に合わせて、
- SQSを使って非同期的にする
- Lambdaではなく、AWS Batchを使う
など、Lambdaの同時実行数を下げるような工夫が必要になります。
また、Provisioned Concurrencyを設定すると常時起動になるのでリクエストがなくてもずっとLambdaの利用料金がかかり続けます。
つまり、サーバーレスの特徴でもある利用料金が使った分だけにはならなくなることに注意しましょう。
まとめ
Lambdaを使えば、サービス同士を疎結合にしたりいいことは多いですが、使い込もうとするほどに注意することも多くなってきます。
Lambda一つの実行の中でベストパフォーマンスが出せるサイジング、コールドスタート対策、一時ファイル容量、同時実行数などなど、注意すべきことは多いです。
また、Lambdaは他のサービスと連携することで最大限の効果を発揮します。そのとき、他のサービスのなんらかの上限や連携時の何らかの遅延など、そのときに注意することも山ほどあります。
Lambdaは簡単に実行できますが、それだけでなく細かい設定や他サービスとの連携ができる柔軟性を備えた奥の深いサービスです。
Lambdaを使いこなして、コストパフォーマンスの高く管理しやすい最高のアプリケーションを目指しましょう。
この素晴らしいサービスであるLambdaを用いたサーバーレスアプリのフレームワークを作成しています。是非こちらの記事もご覧ください。