Lambda はリクエストが来たときにコンテナが立ち上がる。だから利用者がいない間の費用はほぼゼロで、増えれば最大 1000 台まで自動で並列化する。サーバの OS 管理やパッチ適用も要らない。
代わりに、緩和申請できない上限が多い。実行時間は 15 分、同期呼び出しの入出力は 6 MB、メモリは 10 GB で頭打ちになる。初回リクエストにはコンテナを立ち上げる待ち時間、コールドスタートの数百 ms から数秒が乗る。
そのため、ミリ秒応答が要る広告やゲーム、常時接続の WebSocket、常に高負荷な API には向かない。学習用途や社内管理画面、テレビ CM で瞬間的に跳ねるメディア系サイトには合う。Slack Metrics は利用者が自分だけなので、この条件に収まる。
| 上限の項目 | 値 | 効き方 |
|---|---|---|
| 最大実行時間 | 15 分 (900 秒) | 超えると途中で強制終了。長時間バッチは SQS や ECS へ逃がす |
| リクエスト・レスポンス本文 | 6 MB | 同期呼び出しのみ。動画や画像は S3 の署名 URL で直接送る |
| メモリ | 10 GB | 増やすほど料金が上がる |
| /tmp の一時領域 | 10 GB | 呼び出しをまたいで残り、コンテナが破棄されると消える。同じコンテナ内では共有される |
Lambda のコンテナは初期化、呼び出し、シャットダウンの 3 段階を辿る。初期化はコールドスタートとも呼ばれ、ランタイムの起動とコードの読込に続いて Go の init() と main() が走る。設定の読込と DB 接続はここで済ませ、呼び出しの段階では handler だけが走るようにする。
処理を終えたコンテナは数分のあいだアイドルで残る。その間に来たリクエストは init を飛ばして即応答し、これをウォームスタートと呼ぶ。アイドルが続くと AWS がコンテナを破棄し、次のリクエストは再びコールドスタートになる。init が重いと、この待ち時間は 10 秒程度に達する。
グローバル変数と /tmp は、同じコンテナを通る全リクエストで共有される。だからユーザー ID をグローバル変数に置くと利用者間で混線し、/tmp のディレクトリ名を固定すると顧客 A のファイルを顧客 B が上書きする。/tmp は UUID で分けて作る。
Lambda 版は API、バッチ、SQS worker を別の関数にした。タイムアウトは API なら 30 秒で足りるが、バッチと worker は 15 分をフルに使いたい。メモリも用途で変えたい。ログの入れ物であるロググループも関数単位に作られるので、分けるだけで処理種別ごとにログを追える。
ただしコードは分けない。main() が環境変数 MODE を読み、その値で lambda.Start に渡す handler を選ぶ。batch なら EventBridge 用、sqs なら SQS 用、それ以外なら API Gateway 用になる。関数ごとに別のコードベースを持つと、業務の型定義や DB のスキーマを 3 重に管理することになる。
周辺リソースも ECS 版から流用しない。ECS 用の IAM ロールはタスク実行が前提なので、cp-slack-metrics-lambda-stg を新設する。足す権限は AWS の設定値保管サービス Parameter Store の読込と、VPC 内で通信するネットワークインタフェースの作成に絞る。セキュリティグループも同名で新設し、DB 側のセキュリティグループで受け入れる。
Lambda の環境変数画面は値が丸見えで、関数が増えると重複管理になる。だから DB の接続情報は Parameter Store の slack-metrics-stg に、暗号化して保存する SecureString 型で置く。init がそれを読んで環境変数に流し込む。Secrets Manager は自動ローテーションが要る場面の選択肢で、学習用途には費用が高い。
ECS 版が使っていた S3 は候補から外れる。ECS ではコンテナ起動時の 1 回だけ読むが、Lambda ではコールドスタートのたびに読むので、応答遅延に直結する。
ENV と MODE だけは関数に直付けする。ENV は「どこから設定を読むか」を決める値なので、Parameter Store に置くと読む前に判定できない。MODE は関数ごとに違う値なので、共通の Parameter Store には置けない。Parameter Store の値を変えたら、3 関数とも更新しないと反映されない。
| 置き場 | 向く値 | 採否 |
|---|---|---|
| Lambda の環境変数 | 関数ごとに違う値 (MODE)、起動判定に使う値 (ENV) | この 2 つだけ |
| Parameter Store | 全関数で共通の値。SecureString で暗号化、無料 | 採用 (slack-metrics-stg) |
| Secrets Manager | 自動ローテーションなど厳しい要件の秘密情報 | 費用が高いので見送り |
| S3 | ECS 版の設定ファイル置き場 | コールドスタートごとに読むので外す |
EventBridge Scheduler は決めた時刻にバッチ関数を直接起動する。非同期処理は API 関数が SQS の slack-metrics-stg にメッセージを入れ、SQS が worker 関数を起動して RDS に書く。API は投入だけで返るので軽い。
ECS 版の worker は常駐プロセスがメッセージを待つ呼び出しを繰り返し、受け取ったものを処理して自分で削除していた。Lambda 版はキューと関数を紐づける設定を置き、メッセージが来たらキューが関数を起動する。1 件ずつとは限らず、たまった複数件が 1 回の起動にまとめて渡ることがある。
動かないときは、worker 関数に MODE=sqs があるか、IAM ロールに sqs:GetQueueAttributes があるかをまず見る。ワークスペース同期には 30 分に 1 回の呼び出し制限があり、そこで止まっていることもある。ECS 版の API タスクが動いていると、同居する worker がメッセージを横取りする。
Docker イメージのタグはコミットごとに変わる。そのため aws_lambda_function の lifecycle で image_uri を ignore_changes にする。イメージ更新が Terraform の差分に出なくなる。
関数の更新は cloud-pratica-backend の make update-functions で行う。3 関数の image-uri を一括で更新する。GitHub Actions では build と migrate の後に deploy-lambdas を走らせ、サービスごとに並列で更新する。
Parameter Store の値を変えたときも、この関数更新を通さないと反映されない。GitHub Actions を組んであるなら再実行が確実で、検証中なら画面から更新してもよい。
SQS と worker 関数の紐づけは aws_lambda_event_source_mapping で定義する。関数のソース設定とみなして Lambda 側の module に置く。
このコースは Lambda と RDS を直結する最小構成の段階にあたる。API Gateway での公開、Cognito 認証、RDS Proxy、WAF は後続コースで足す。
| リソース | 名前 |
|---|---|
| ECR | slack-metrics-lambda-stg |
| IAM ロール | cp-slack-metrics-lambda-stg |
| セキュリティグループ | cp-slack-metrics-lambda-stg |
| Parameter Store | slack-metrics-stg |
| SQS キュー | slack-metrics-stg |
| Lambda 関数 | slack-metrics-api-stg / slack-metrics-batch-stg / slack-metrics-worker-stg |