AWS Lambda@Edge 躓きポイント10連発

この記事は AWS初心者 Advent Calendar 2018 19日目の記事です。

最近業務でLambda@Edge触ったので、自分が引っかかったポイントなど覚えているうちにメモも兼ねて。

1. 東京リージョンは無い

Lambda@Edgeは通常のLambdaと違い東京リージョンはありません。

自分は米国東部(バージニア北部)を使ってました。Lambda@EdgeとLambdaを行ったり来たりする場合は注意です。

早く日本にも来てほしいなぁ〜

2. 同時実行数に制限がある

Lambda@Edgeを使う上で注意しないといけないのは同時実行数の上限を超えないことです。

上限はデフォルトで1000ですが、これはAWSルートアカウント毎に割り当てられています。 つまり同一アカウント上のその他全ての関数とこの1000という数字を奪い合うことになります。

f:id:romiogaku:20181205173012p:plain

また、この数字は制限引き上げのリクエストから緩和することができます。

3. CloudWatchで関数のInvocationsを可視化するとき、「統計」を「合計」にする必要がある

大抵の人は躓かないと思いますが、デフォルトで「平均」になってますので要変更です。

f:id:romiogaku:20181205173217p:plain

また、同時実行数を可視化する場合は統計を「最大」にしておくと良いでしょう。

f:id:romiogaku:20181205173348p:plain

4. ものによってはとんでもない頻度で実行される

これは実際にやっちまった案件なんですが、Lambdaを使うにあたってお試しで適当な関数を作ってたんです。

ある日CloudWatchの同時実行数見たら500を超えていました。

実はお試しで作った関数のイベントトリガーがS3のPUTイベントになっており、誰かがファイルをS3にPUTする度に実行されていました。消し忘れです。

リリース前に気づけて良かった・・・

5. 同時実行数の制限解除してもらっても反映されていない(ように見える)

AWSに問い合わせてLambdaの同時実行数上げてもらったんですが、東京リージョンである通常のLambdaのほうは上がってるのにLambda@Edgeのほうは上がってないように見えました。

aws cliで確認しても関数の置いてあるであろう米国東部(バージニア北部)リージョンは1000のままです。

$ aws lambda get-account-settings
{
    "AccountLimit": {
        "CodeSizeUnzipped": 262144000,
        "UnreservedConcurrentExecutions": 1000,
        "ConcurrentExecutions": 1000,
        "CodeSizeZipped": 52428800,
        "TotalCodeSize": 80530636800
    },
    "AccountUsage": {
        "FunctionCount": 13,
        "TotalCodeSize": 21042275
    }
}

実はこれ、東京リージョンからのリクエストは東京にレプリケートされた関数で処理をされるため、東京リージョンからのみのリクエストであれば東京リージョンの緩和で問題は無いとのこと。 まぎらわしい!

6. CloudWatchにログが出ない(ように見える)

これもリージョンによる引っかかりポイントなんですが、Lambda@Edge関数の「モニタリング」タブをクリックしてもCloudWatchメトリクスの概要は表示されません。

日本からのアクセスは東京にレプリケートされた関数で実行されるので、CloudWatchログ出力先も東京リージョンになります。でもこの画面自体は米国東部(バージニア北部)なので何も表示されてないということですね。

f:id:romiogaku:20181205173516p:plain

ログを見たければ「CloudWatchのログを表示」ボタンを押す必要がありますが、リージョンは「バージニア北部」とかになっているはずなので「東京」に変更してください。

東京リージョン早く来てくれー!

7. 関数の削除は関数のレプリカがCloudFrontによって削除された場合のみ

関数を削除する前に、CloudFrontとの関連付けを削除する必要があります。

f:id:romiogaku:20181205173540p:plain

これやってからじゃないと消せません。

8. イベントによって関数自体の容量制限が異なる

Lambda@Edgeの制限にもあるように、 Origin Request/Responseは50MB、Viewer Request/Responseは1MBという制限があります。

Nodeで書いてもnode_modulesを巻き込むだけで1MBは軽く超えてしまうので注意です。

9. エラー時はViewer Responseイベントに紐づけた関数は実行されない

「エラー時は特定のページへリダイレクトする」という要件がありまして、最初Viewer Responseをトリガーに作ってたんですがうまくいきませんでした。

理由はこちらにありました。 https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-http-status-codes

オリジンから 400 以上の HTTP ステータスコードが返された場合、ビューワーレスポンスイベントに対して Lambda 関数は実行されません。

代わりにOrigin Responseを使いましょう。

ちょっと脇道に逸れますが、エラー時ののCache TTLはデフォルト300なので、CloudFrontのError Pagesタブから必要に応じて設定しましょう。

f:id:romiogaku:20181205173559p:plain

10. ResponseイベントででUser-Agentがリクエスト時のものと異なる

これはLambda@EdgeというよりCloudFrontのデフォルト設定の特徴なのですが、CloudFrontを通過するとUser-Agentの値がAmazon CloudFrontに書き換えられます。つまり、

f:id:romiogaku:20181205173617p:plain

Origin response、Viewer responseでUser-Agentを利用したい場合は一工夫する必要があります。

CloudFrontにはどのリクエストヘッダを引き継ぐか設定できる項目があるので、User-Agentを指定することも出来ます。 ただしこのやり方はキャッシュ効率が悪いので、PC/スマホ/タブレットの判断することだけが目的なのであれば以下のようにしましょう。

f:id:romiogaku:20181205173628p:plain

CloudFrontのBehaviorsから以下のようなヘッダを追加します。

  • CloudFront-Is-Mobile-Viewer
  • CloudFront-Is-Tablet-Viewer
  • CloudFront-Is-SmartTV-Viewer
  • CloudFront-Is-Desktop-Viewer

Lambda@Edgeではこれらの値(true/false)を見て判断します。

サンプルは

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html#lambda-examples-redirecting-examples

の「デバイスに基づいて異なるバージョンのオブジェクトを供給する」を参考にすると良いでしょう。

おわりに

Lambda@edgeはLambdaと似てるんですが、CloudFrontやリージョンについて注意深く見ていかないと結構ハマるポイントがありました。

AWS re:Invent 2018ではLambdaに関する発表が色々ありましたが、「Lambdaだけだよ、Lambda@Edgeは別だよスマンな」的なものも結構あると思います。 とはいえAWSはどんどんアップデートされていくので、来年の今頃どうなっているか楽しみですね。