Provisioned Concurrency を設定した Lambda 関数を ALB にぶら下げるときの注意点

記事タイトルとURLをコピーする

結論

  • Provisioned Concurrency は関数のバージョンではなくエイリアスに対して設定しよう
  • ドキュメントにもあるように関数のエイリアスをロードバランサーのターゲットグループに登録しよう

ロードバランサーが常に現行バージョンの Lambda 関数を呼び出せるようにするには、関数のエイリアスを作成し、ロードバランサーに Lambda 関数を登録するときに関数 ARN にエイリアスを含めます。

ターゲットとしての Lambda 関数

はじめに

こんにちは、ディベロップメントサービス課の保田(ほだ)です。

6月から短パンで過ごすことに慣れてしまい、(私服と言えど)長ズボンを穿いてオフィス出社していたころがもはや想像できなくなっています。

導入

要件によっては Lambda 関数を ALB のターゲットに登録して、 ALB 経由で実行したいときもあるかと思います。

また、要件によってはその Lambda 関数に Provisioned Concurrency を設定して指定数の実行環境をプロビジョニングしておきたいこともあるかと思います。

このような状況下で、設定を間違うと ALB 経由で呼び出している Lambda からのレスポンスが思ったように速くならず「どうやらコールドスタートが起きているみたいだぞ」、ですとか「Lambda をデプロイしたとき ALB の向き先を最新のものに切り替える手順が面倒だぞ」といった事態を招く可能性があります。

個々のドキュメントの記載をつなぎ合わせれば自然と望ましい設定にできていることもあるかと思いますが、改めてなぜそうすべきなのかを解説していきます。

Provisioned Concurrency

Provisioned Concurrency を利用すれば、 Lambda 関数の実行環境をウォームスタートできる状態で指定数確保しておくことができます。

docs.aws.amazon.com

さて、この Provisioned Concurrency ですが設定するには Lambda 関数のバージョンとエイリアスについて理解していないといけないので、ここから先しばらく説明します。

知ってるよ!という方は 7. 再び Provisioned Concurrency のセクションまで飛んでください。

Lambda 関数のバージョンとエイリアス

Lambda 関数にはバージョンとエイリアスが設定できます。順に見ていきましょう。

docs.aws.amazon.com

docs.aws.amazon.com

バージョン

バージョンはある時点の Lambda 関数のスナップショットであり、画面キャプチャからもわかるようにその時点での最新版( $LATEST )を新しいバージョンとして作成することになります。 タイムアウトやメモリーなど、ソースコード以外の設定値も保存されます。

f:id:swx-kazuma-hoda:20210603200629p:plain
バージョンを作成

特定のバージョンの関数を表す Lambda は 修飾 ARN により一意に特定されます。 関数名の後ろに :2 がついていますが、それです。バージョンを作成するごとにこの数字がインクリメントされていきます。

arn:aws:lambda:ap-northeast-1:123456789012:function:provisioned-concurrency-test:2

一度作成したバージョンのコードや設定内容は後から変更することはできません。

Lambda の更新時はこのバージョンごとにアクセスを振り分けたりすることで、カナリアデプロイメントなんかも実現できますというわけですね。

また、 非修飾 ARN と呼ばれる Lambda 関数の ARN があります。

arn:aws:lambda:ap-northeast-1:123456789012:function:provisioned-concurrency-test

これは $LATEST という特殊なバージョンを指すものになっており、要するにその時点での最新のコードに対応します。 「特殊」と書いたのは、この $LATEST バージョンのコードはいくらでも変更でき、特定のバージョンの中身はあとから変更できないという仕様に当てはまらないからです。

エイリアス

エイリアスはこのバージョンに対して貼るものになっています。

エイリアス自体は $LATEST バージョンに対しても設定できます。

f:id:swx-kazuma-hoda:20210603200704p:plain
エイリアスを作成

また、エイリアスは向き先のバージョンを後から変更できます(同時に複数のバージョンを指すことはできません)。

ですので向き先のバージョンを Lambda 関数をデプロイするたびに切り替えるようにすれば、バージョンがどんどんインクリメントされても常に同じ修飾 ARN で呼び出すことが出来るわけですね。

修飾 ARN はバージョンの時と似たような形になります。 当然数字( 1 とか 2 とか)はバージョンの命名と被ってしまうのでエイリアス名として使えません。

arn:aws:lambda:ap-northeast-1:123456789012:function:provisioned-concurrency-test:dev

再び Provisioned Concurrency

ここで Provisioned Concurrency の話に戻ってきます。

Provisioned Concurrency はバージョンかエイリアスに対して指定できます。が、 $LATEST に対しては設定できません。

非公開バージョン ($LATEST) を参照するエイリアスにプロビジョニングされた同時実行数を割り当てることもできません。

docs.aws.amazon.com

ですので、 $LATEST 以外のバージョンかもしくは向き先が $LATEST ではないエイリアスをターゲットに指定しなくてはなりません。

ALB のターゲット

さて、 ALB のターゲットグループに Lambda 関数を指定する場合、バージョンかエイリアスを指定します。 このバージョンは $LATEST を含みます。

f:id:swx-kazuma-hoda:20210603200746p:plain
ターゲットに Lambda 関数を設定

ですので、何も考えずに $LATEST バージョンを指定すれば、 ALB 経由で呼び出される Lambda は常に最新状態のものということになります。 現にマネジメントコンソールから設定すると、デフォルトでは $LATEST が選択されています。

じゃあそれでいいじゃん、となりそうですがここにProvisioned Concurrency が絡むと話が変わってきます。 そうです。Provisioned Concurrency は $LATEST バージョンに対して設定することはできません。

直前に述べたように $LATEST 以外のバージョンかもしくは向き先が $LATEST ではないエイリアスをターゲットに指定しなくてはなりません。

ではバージョンとエイリアスのどちらが良いか、ですが、 ターゲットグループは一度指定した ARN を後から変更できない 仕様を考慮すると答えはおのずと見えてきます。

ちなみに変更したい場合はターゲットグループから登録解除し、新たに作成したターゲットをまたターゲットグループに登録する必要があります。(めんどくさい)

はい、という訳で冒頭のこのドキュメントに行きつきます。

ロードバランサーが常に現行バージョンの Lambda 関数を呼び出せるようにするには、関数のエイリアスを作成し、ロードバランサーに Lambda 関数を登録するときに関数 ARN にエイリアスを含めます。

ターゲットとしての Lambda 関数

まとめると、あるべき姿はこうなります。

  1. Lambda 関数を更新したら新しいバージョンを作成する
  2. Lambda 関数の 1 のバージョンが向き先となるエイリアスを作成する
  3. Provisioned Concurrency は 2 のエイリアスに対して設定する
  4. ターゲットグループのターゲットには Provisioned Concurrency を設定したエイリアスを指す Lambda 関数の修飾 ARN を指定する

こうすることで、公開する Lambda 関数が更新されても、バージョンの作成とエイリアスの向き先変更だけやれば常に同じ ALB で Provisioned Concurrency の効いた Lambda 関数を呼び出せる、という訳です。

また、 バージョンの作成とエイリアスの向き先変更 の手順もドキュメントの機械翻訳がヤバいことでおなじみの AWS SAM(Serverless Application Model) にて AutoPublishAlias を設定すれば自動でやってくれます。

  • AutoPublishAlias: AWS SAM では、このプロパティを追加し、エイリアス名を指定することで、以下を実行します。
    • Lambda 関数の Amazon S3 URI に対する変更に基づいて、新しいコードがいつデプロイされるかを検出します。
    • 最新のコードでその関数の最新バージョンを作成して発行します。
    • Lambda 関数の最新バージョンを参照するエイリアスを指定された名前で作成する (エイリアスがまだない場合)。関数の呼び出しでエイリアスを利用するには、エイリアス修飾子を使用する必要があります。Lambda 関数のバージョニングとエイリアスに慣れていない場合は、AWS Lambda 関数のバージョニングとエイリアス。

docs.aws.amazon.com

おわりに

完全に私事ですが Lambda 関数に $LATEST 以外のバージョンを作ったりエイリアスを作成したり、はたまた Provisoned Conccurency を使うような機会も今までありませんでした。 しかも ALB 経由で Lambda を呼び出すこと自体も初めてだったので、当初は色々混乱してしまいました。

せっかくなので、そのあたりの回り道した過程もまとめてみましたという訳です。

今後似たような事態に遭遇して「なんかよく分からんがレスポンス速度からして多分 Provisoned Conccurency 効いてないのでは?」となって困っている方の参考になれば幸いです。