KAKEHASHI Tech Blog

カケハシのEngineer Teamによるブログです。

Lambda zipアーカイブデプロイを深堀りしてコールドスタートを速くしよう

ここ最近のトレンドとして、Vercel, Cloudflareとサーバレスにおけるコールドスタート高速化周りでしのぎを削っており Lambdaも様々取り組みがなされています。それでもLambdaはシェアが大きいこともあり、コールドスタートが話題になることは多いです。この記事では、あまり語られないファイルサイズの観点からコールドスタート高速化にアプローチします。

zipアーカイブに着目するモチベーション

Cold Start時はS3からコード一式をダウンロードするため、サイズが小さいほうがCold Startが短くなります。

また、解凍後のファイルサイズが250MBまでという制限もあります。こちらは上限緩和不可能です。なお直接アップロードする場合はzipのサイズは50MBまでで、これ以上だとS3バケットを準備してそちらにアップロードする必要があります。

とにかく不要なものを削ればCI/CDが早くなることも期待できます。 余計なコードやライブラリを削ることができればセキュリティ侵害時の影響範囲も削減できる可能性があります。

よく使うZip形式でのアップロードについて述べてきましたが、コンテナイメージによるデプロイでも結局サイズが小さいほうが有利です。

* 以下LambdaだけではなくLambda Layerのサイズ減にも適用できます

まずはデプロイしたzipファイルの中身を確認する

zipサイズが想定より巨大になってないでしょうか?マネジメントコンソールのLambda画面からzipをダウンロードして内訳を見ましょう。現場現物現実からです。

zip解凍後のディレクトリサイズ内訳をMacで見るサンプル

du -sh * 2>/dev/null | sort -hr

サイズが大きいLambdaを一覧化する

AWS Config Advanced Queryで確認可能です。アカウントを横断して確認できます。

SELECT
  accountId,
  resourceId,
  configuration.codeSize,
  configuration.runtime
WHERE
  resourceType = 'AWS::Lambda::Function'
  AND configuration.codeSize > 1234567 # byte
ORDER BY
  configuration.codeSize desc

大きさの大小だけではなく、同一サイズのものにも目を光らせましょう。バイト単位で同一なのは何かが怪しいですね。

デプロイサイズを小さくするtips集

カケハシではTypeScriptとPythonを使っているためこの2言語で例示します。

開発用資産に目を凝らす

mypyのバイナリが入っていて50mb消費していることがありました。requirements.txtを開発と本番で分けていてもsqlalchemyの依存関係経由で本番にも入っていたことが原因です。

想定外の不要物が入っていることがあるので目視またはパッケージマネージャで確認しましょう。

Lambdaアーティファクトがうまく分割できていない

Lambdaを分割していて関数名が違うのに中身もサイズも全部同一であることがあります。デプロイの設定がうまくいってないようでした。モノリポならなおさら膨らむリスクがありますね。

依存関係の解決に問題

opensslが2バージョン分入っている事例がありました。目視またはパッケージマネージャで確認しましょう。

TypeScript: 一般的なフロントエンドのプラクティスを適用する

まずesbuildなりでビルドしましょう。ビルドせずにそのままだとサイズが膨らみます。フロントエンドに詳しくない人がCI/CDだけ設定すると起きるようです。フロントエンド開発者に確認して一般的なフロントエンド設定を導入しましょう。

各種bundle analyzerで可視化しバンドルサイズを測定することができるので活用しましょう。

フロントエンドではパフォーマンスのためにファイルサイズが重視されるため、TypeScriptは改善意識が高くなる面があります。

あえてニッチな世界

良く使われるパッケージのいくつかはNode.js 4 (!!)対応のpollyfillでサイズが異常に膨らんでいます。すっきりしたパッケージでoverideすることで、インストールが高速化されディスクにも優しくなります。

# npmではなくnpx
npx nolyfill # 検査のみ
npx nolyfill install # 置き換え

置き換えリスト

CommonJS(CJS)はESMよりファイルサイズが膨らむ傾向にあります。仕組み上通常のパフォーマンス面でも不利なのでESM対応のモジュールが望ましいです。

e18eイニシアティブにも注目しましょう

Pythonの大技 ソースコード全削除

Pythonはソースコード(.py)をバイトコード(.pyc)に変換して読み込みます。Zipには.pyと.pycの両方が含まれており、.pycがあれば.pyファイルを全削除しても動作します。

python -m compileall -b .
find . -name "*.py" -delete

注意点としてスタックトレースでソースコードが表示されなくなることがあります。ただし、特にサードパーティモジュールのスタックトレースはアプリケーションのデバッグにはほぼ役に立たないのと、本番運用では適切にエラーハンドリングしてエラーメッセージを出すのが筋であることから、そこまで問題ないことが多いでしょう。

CDKの場合はデプロイ時にコマンドフックで設定するとよさそうです。

最後に

Lambdaは抽象化されており便利ですがその分うっかりが発生しやすいです。セキュリティの観点でも不要なパッケージは望ましくないですし、Lambda以外でも起動や初期処理が早いに越したことはないでしょう。どんどん削除しましょう。

文責: 高木

おまけクイズ

Lambda関数のサイズ削減の利点について、以下の選択肢からもっとも不適切なものを選んでください。

A. CI/CDが早くなる可能性
B. セキュリティ侵害時の影響範囲が削減できる可能性
C. アプリケーションのデバッグが不要に
D. Cold Startの時間短縮

このクイズはGitHub Copilot Chat経由で生成されました。