AWS Lambda いろいろまとめてみた

はじめまして。こんにちは。ポーのかあちゃん＠SRA関西事業部 です。（ポーは[★ここ★](https://www.instagram.com/polaris1020/)）
[SRA Advent Calendar 2016](http://qiita.com/advent-calendar/2016/sra)の23日目を担当します。よろしくお願いします。

さて。なにを書こうか悩みましたが、お仕事で[AWS Lambda](https://aws.amazon.com/jp/lambda/)を利用することがあったので、それについていろいろまとめたいと思います。

よろしければ最後までおつきあいください。

# AWS Lambda って？
サーバレスで実行可能なコンピューティングサービスです。

AWS上でアプリケーションやAPIなどを実装する場合、EC2インスタンス上にサーバ構築することもできますが、Lambdaであればそのような環境を用意することなくアプリケーションを作成・実行することができます。自動でスケールもしてくれます。
あらゆる言語で実装することができる上に、VPCにも対応しました。

運用の手間や維持コストを軽減できるので、手軽で便利なサービスと言えます。

ただ、ちょっと制約事項が多いのが難点です。

# 知っておきたい制約
公式の情報は[ここ](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/limits.html)にあります。

- 1回の処理の制限時間がある（設定で変更可能だが、最大５分までしか指定できない）
- 同時実行数に制限がある（デフォルトで100、サポートセンターにお願いすれば制限引き上げ可能）(※実際は100%使い切れないようです)
- 割り当てメモリ量に制限がある（最大で1536MB）
- リクエストおよびレスポンスのサイズ制限がある（RequestResponseではリクエスト・レスポンス共に6MB、Eventではリクエスト128KB）
- Lambda関数のデプロイパッケージサイズに制限がある（詳しくは公式参照）

比較的余裕のある制限値のように感じるかもしれませんが、使い方次第では十分足かせになる可能性があるので、注意が必要です。

# はまりどころ
意外とはまることが多かったので、代表的なものを書いてみます。

### ■どこの環境でだれが起動するかわからない
AWSが勝手にやってくれているので、Lambdaが起動する環境およびユーザは自分ではコントロールできません。（仮に「ドコダレ問題」とします）
このことが、他のはまりどころに意外と影響を及ぼしていたりするので、意識しておいたほうがよいかと思います。

### ■初期の処理時間が遅い
LambdaファンクションをJavaで実装する場合に注意して欲しい点です。
上記「ドコダレ問題」のとおり、Lambdaが起動する環境はどこになるかわかりません。
初めて起動した環境では、クラスロードに時間を要するため、かなりの処理速度低下が見られます。
新しい環境で実行するたびにこの現象が発生するので、文字通りの「初回のみ」ではないのがいやらしいですね・・・。

### ■/tmpの利用
/tmpを使いたいな、ということがあるかもしれないので、注意点をば。

1. /tmpを利用する上でサイズ制約がある。([公式サイト](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/limits.html)参照)
2. /tmpに残してしまったファイルをその後操作できないと思ったほうがよい。

2.の方は、またまた出ました「ドコダレ問題」です。どこで実行されるかわからないので、同じ/tmpの下のファイルであっても前回起動時と同じファイルとは限りません。仮に同一環境だったとしても、ユーザが異なるせいでパーミッションエラーになる、なんてことも。

### ■コスト・メモリ試算に悩む
Lambdaのコスト試算は、

- リクエスト回数
- 処理時間
- 他サービスとのデータ転送量

によって計算できます。その内、「処理時間」に関しては設定するメモリ量によって料金が変わるため、メモリ試算も重要なポイントになります。

メモリについては、１回のLambda処理で使うと考えられるメモリ量をまず試算しますが、当然のごとく、メモリ量によって処理速度も変化します。
つまり、処理をするのに十分なメモリ量を確保しつつ、処理速度とコストのバランスがもっとも良いところに落ち着けるのがBetterです。
製造段階までは内部データサイズなどで試算したメモリ量で設定し、単体テスト完了後あたりにメモリ設定を変更しながら処理速度を計測してコストをグラフ化することをおすすめします。

（参考：[AWS Lambda メモリ容量による処理性能の違い](https://www.business-on-it.com/techblog/aws-lambda-performance-check/)）

### ■LambdaのタイムゾーンはUTCである
Lambdaファンクションをどこのリージョンにおいていようと、new Date()などで取れる時刻はUTCのものです。
仕事ではNode.jsで実装していたのですが、単体テストをローカル環境でmochaを用いて行っていたところ、当たり前のようにDateオブジェクトの時刻は日本時間になり、想定とは異なる時刻になってみんながてんやわんやしました。

### ■エラー時の自動リトライがある
公式サイトは[こちら](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/retries-on-errors.html)。

Lambdaの起動は、以下の種類があります。
1.および2.ではメモリオーバーやタイムアウトなどのエラー発生時にAWSによる自動リトライが行われます。

1. Kinesis Streams, DynamoDB Streamsをイベントソースとする場合
2. Kinesis Stream, DynamoDB Stream以外のイベントソースで非同期呼び出しされる場合
3. 同期呼び出しされる場合

1.では、対象のストリームデータの有効期限内であれば、例外時にAWSによる自動リトライが繰り返されます。この「有効期限」も結構長い場合があるので、リトライが続きすぎないようにすることも考慮したほうが良いかもしれません。これについては、Kinesis Streamsとの組み合わせで具体例を後述します。

2.では、AWSによる自動リトライは2回まで実施されます。2回目の自動リトライでもエラーになった場合、Lambdaファンクションにデッドレターキュー (DLQ) を指定していないと、通知もされずにそのまま破棄されるので注意が必要です。

3.では、呼び出し元へ429 エラーが渡ります。リトライが必要であれば、呼び出し元にその仕組みを用意しておく必要があります。（詳しくは[公式サイト](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/retries-on-errors.html)参照）

# （参考）Kinesis Streams + Lambda
Kinesis Streams をイベントソースに指定している場合のLambdaの動きを簡単にまとめました。ご参考になれば。

- Kinesis Streams のイベントタイプはプルモデル。Lambdaが定期的にストリームをポーリングし、対象となるデータがあれば起動する。
- Lambdaは、対象となるストリームのシャードごとに起動する。
- 一度の起動で渡ってくるデータ数は、設定したバッチサイズ以上のデータがあってもバッチサイズどおりとは限らない。
- データの順序は保証される。
- 自動リトライが発生した場合、引数はリトライ前とまったく同じものである。（つまり、データ数もその中身と順序もまったく同じ）
- 自動リトライは、データセットの中で一番新しいものの有効期限が来るまで行われる。
- 次のデータセットで実行されるのは、前のデータセットでLambda処理が正常終了したか、前のデータセットの自動リトライが繰り返されて有効期限切れしたか、である。  

# まとめ

では、ざっくりとまとめます。

- AWS Lambda はサーバなくても動かせて、コストも使った分だけと良心的。
- 制約事項が多め。
- 運用を考えるとはまりどころがけっこうあるので、しっかり利用背景を考察してから導入しましょう。

他にもいろいろありますが、長くなりそうなのでこのへんで。
少し癖がありますが、それを理解した上で使えばとてもお手軽なので、ぜひ一度使ってみてくださいね。

今日はクリスマスイブイブな３連休初日。
カレシ・カノジョできててもできてなくても、家庭あってもなくても、素敵なクリスマスをお過ごしくださいね！
そして来年も、[SRA](http://www.sra.co.jp/)をよろしくお願いしますm(_ _)m