🎉

今更ながらLambdaプロキシ統合でプロキシリソースの使用有無について比較してみる

2023/12/09に公開

概要

この記事はAWS Lambda と Serverless Advent Calendar 2023シリーズ1、9日目の記事です。

  • APIGateway+Lambdaの構成でAPIを作るときの構成は組み合わせパターンが多い
  • その中でもLamdbaプロキシ統合を使うことが多い気がする(主観)
  • Lambdaプロキシ統合を使う場合でもプロキシリソース({proxy+})の使用有無について比較

結論として使用有無のどっちの方が優れているかを述べていません。いくつかの観点で比較して要件や開発組織にあったものを選ぶべきというのが結論になります。

また、Lambdaプロキシ統合およびプロキシリソースについては2018年ごろ(おそらく)リリースされたもので真新しい機能ではありません。とはいえ、自分としてもその使い分けについて明確な基準や比較軸を持っていなかったり、そのような記事をあまり見かけなかったので書いてみることにしました。

Lambdaプロキシ統合とは

APIGateway + Lamdba の統合タイプは、大きく分けて2種類ある

  • Lambdaプロキシ統合:
    • 出力形式に制約はあるが、QueryStringなどのリクエストに含まれる情報にアクセスが容易
    • APIGateway側の処理をあまり意識しなくてよく、Lambdaの処理に集中しやすい
  • Lambda非プロキシ統合:
    • 出力形式などの自由度は高いが、QueryStringを受け取るために一手間必要
    • APIGatewayでマッピングテンプレートを設定する必要がある

この違いについてはこの記事がわかりやすかったです。
https://qiita.com/yuuwatanabe/items/a3bd65e709f20574b6db

この2種類があるのですが、この記事では、Lambdaプロキシ統合に絞った話をしようと思います。なぜかというと私個人の経験や主観によるところも多いのかもしれませんがなるべくバックエンドのルーティングを含めたロジックをLamdbdaのソースコードだけで完結させたいケースが多く、APIGateway + Lambda の構成でREST APIを構築する際は、Lambdaプロキシ統合を使うことが多いためだと思っています。

そうではなく、Lambda非プロキシ統合の方がメリットが多い!よく使う!みたいな話はシンプルに興味があるので聞いてみたいです。一般的になりつつある?APIGateway + Lambdaの構成ですが、この辺の話を調べると2018,2019年ごろの記事が多く最近の記事は少ない気がしたのですが、世の中的にどうしているのかは気になります。

Lambdaプロキシ統合を使う上での2つの選択肢

プロキシリソース({proxy+})を使わないパターン

特徴を簡単に言うと、
リソースとメソッドごとに定義する

実際のAPIGatewayとしては、このように、リソースとメソッドごとに定義されている状態になる。

このような定義はAPIが大きくなればなるほど大変になってくるので、OpenAPIのyamlファイルで書かれた定義を使ってAPIGatewayのインテグレーションをすることができるSpecRestApiと言うものを使うことで負担が軽減します。

詳しくはこちらの記事がわかりやすかったのでご参照ください。
https://qiita.com/stake15/items/2616a568593d48e5bd16

プロキシリソース({proxy+})を使うパターン

プロキシリソースを使うというのは、本記事では以下のことを指します。

  • greedy パス変数 {proxy+} を使用してプロキシリソースを作成します。
  • プロキシリソースに ANY メソッドを設定します。
  • Lambda 統合タイプを使用してリソースおよびメソッドをバックエンドに統合します。

引用元の公式ページ:
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html

実際のAPIGatewayとしては、このように、/{proxy+} にANYメソッドがあるパターンです。

こうしたインテグレーションをした上で、Goで実装する場合に、github.com/aws/aws-lambda-go/events のAPIGatewayProxyRequestを使うとHTTP リクエストをそのまま扱える。

とにかく特徴としては、
リソースやメソッドごとにインテグレーションを設定する必要がなくなる。

プロキシリソース({proxy+})の有無で比較軸

ここからようやく本題の2つの方法の比較をしていきます。

開発のしやすさ

主にローカル環境で開発する際の開発のしやすさを指します。
APIGateway + Lambdaをローカル開発する際の選択肢はざっと以下のような方法があるかと思います。

  1. デプロイしながら動作確認する
  2. ローカルにエミュレートして動作確認する
  3. Dockerとして動かす

1.の方法は、
一見、時間がかかるので効率が悪そうに見えるかもしれませんが、cdkのwatch機能を使って、cdk deploy --hotswapのようなホットスワッピング機能を使うことでそこまで反映に時間がかからず実際にデプロイして動作確認することができます。シンプルなLambda+DynamoDBだけの構成などの場合は他に準備もいらないので手軽に実現することができます。一方、RDSのリソースが必要な場合は環境を用意する手間とRDSのリソース費用などがネックになることがあります。

2.の方法は、
SAM(CDK) Localや、JavaStackなどを使ってローカルPC内にAWS環境をエミュレートする方法になります。メリットとしてはローカルに環境を立てるので個人環境として動作確認がしやすいこととAWS料金がかからないことです。デメリットとしてはエミュレート環境を構築するのに工数がかかることなどがあると思います。

3.の方法は、
Lambda+RDSの構成でよくあるWebフレームワークの開発と同じ要領で開発をする想定です。Lambdaのhandlerをデプロイ用とDocker用で分岐する必要はあるのと他のAWSリソースとの連携が難しい点がデメリットですが、SWEが慣れ親しんだ方法で開発ができるメリットがあると思います。

この項目の比較は、開発者の経験(慣れ)やアーキテクチャによるところが大きい印象です。1.~3.のどの方法でも構成にマッチしていればストレスなく開発を進めることができるのではないでしょうか。

実装面

  • CDKなどのIaCの実装コスト
  • ルーティング処理の実装コスト

の2つがあると思います。

CDKなどのIaCの実装コストについては、プロキシリソース({proxy+})有 の方がコストは低いと思います。ただ、OpenAPIでyamlを定義している状態だったりすると差分がほとんどなくなるなど必ずしもプロキシリソース({proxy+})有が実装コストで優位ではないかなという印象です。

ルーティング処理の実装コストについては、APIGatewayProxyRequestなどを使ってHTTPリクエストを直接扱えるようにするか、eventからqueryStringを取り出す実装をするかで差がある・Lambdaへの依存度が変わると思いますが、プロキシリソース({proxy+})の有無では差がないという印象です。
(記事を書く前は、プロキシリソース({proxy+})の有 だとルーティング処理がHTTP処理のままで、プロキシリソース({proxy+})の無 だとLambdaに依存した実装をしなければならないという先入観がありましたがどちらでもAPIGatewayProxyRequestを使えそう(未検証)なので優位差はないように感じました。)

メトリクス(CloudWatch)

個人的には、ここは大きい差だと思います。

  • 1つ1つのリソースとメソッドを定義する、プロキシリソース({proxy+})無 のパターンだと、リソース*メソッド毎にレイテンシーやカウント、エラーのメトリクスが取れる

逆に、プロキシリソース({proxy+})有の場合は取れないですが、DatadogなどのSaaSを入れるとか別の方法でメトリクスを取るよっていう場合はどちらのパターンも同じメトリクスが取れるようになると思うので差分がなくなると思うので何でメトリクスを取るかに依存します。

チューニング面

この観点は、Lambdaのリソースやタイムアウト値などのチューニングを行えるかどうかという観点です。この観点では、プロキシリソース({proxy+})無の方が、元々リソースやパス毎にインテグレーションを定義するという観点からスペックの違うLambdaを複数種類用意したりするのと相性が良いと思います。プロキシリソース({proxy+})有 の方でも分岐の数が少なければ実現できないことはないと思いますが、細かい設定がしにくかったり、初見でわかりにくいインテグレーションになるかと思います。

まとめ

いかがでしたでしょうか。
自分でこのテーマで何か書こうと思ってから、いざ書こうとしてみるとLambdaのインテグレーション周りの用語や正確な理解について実はよくわかっていないことに気付くことになり、調べたりすることが多かったというのが一番の感想です。

想像ですが、Lambdaのインテグレーション方法どうするかについて決める際に、過去経験したものを踏襲したり、何かしらで調べて出てきたものをとりあえず使ってみて比較とかはあまりせずに決めることもあるのではないでしょうか?(特大ブーメラン)
そういった意思決定をしている場合にちょっと立ち止まって比較検討する材料となれば幸いです。

また余談ですが、AWS Distro for OpenTelemetry LambdaというOpenTelemetryをLambda Layerで動かす仕組みや先日のAWS re:Invent2023で発表されたCloudWatch Signalsなどオブザーバビリティ周りのアップデートも活発なAWSです。比較軸としてあげたメトリクスについては特にこの辺りの機能のアップデートの影響を受けるケースが多いのかなと思うと同時に、CloudWatch SignalsはECSやLambdaなど環境やプログラミング言語問わず使えるようになると良いなと思いました。

それでは以上で、Lambdaプロキシ統合でプロキシリソースの使用有無について比較についての話は終えようと思います。良いサーバーレスライフを🎉

Discussion