Claude CodeでLambdaのメモリを最適化 — Power Tuningの結果から値を選ぶ
AWS Lambda Power Tuningの測定結果をclaude -pに渡して費用最小と速度優先を比べ、SAMのMemorySizeを直して本番相当の負荷で再確認する手順。測定とデプロイは人が握ります。
Lambdaのメモリは、作成時の128MBのまま、あるいは「念のため1024MB」で置いたまま残りがちです。メモリを増やすとCPUも増えるため、実行時間が縮んで、結果として安くなる関数もあります。逆に、何も縮まずに単価だけ上がる関数もあります。
どちらなのかは、関数ごとに測らないと分かりません。ここでは、AWS Lambda Power Tuningの測定結果をClaude Codeに読ませて候補を比べ、SAMテンプレートのMemorySizeを直し、本番相当の負荷で確かめ直すところまでを順に進めます。測定の実行とデプロイは人が握り、Claude Codeには数字の読み取りとテンプレートの編集だけを任せる構成です。
費用を決めるのは「実行時間×メモリ」の積
Lambdaは、割り当てたメモリに比例してCPUを割り当てます。メモリは128MBから10,240MBまで1MB刻みで設定でき、1,769MBで1 vCPU相当になります。
課金は、コードの実行が始まってから戻るまでの時間を1ms単位で切り上げて数え、単価はメモリ量で決まります。x86とArmでは、1ms当たりの単価表が別に載っています。メモリを倍にすると1msの単価は倍になるので、実行時間が半分以下にならなければ、費用は上がります。
ここに、見直しが「下げれば安い」では済まない理由があります。
- CPUに縛られる処理は、メモリを増やすと実行時間が大きく縮む。単価増を上回れば、速くて安くなる
- ネットワークや外部APIの待ちが大半の処理は、メモリを増やしても縮まない。単価だけが上がる
- メモリ不足で苦しんでいる処理は、増やすと劇的に改善することがある
Power Tuningのリポジトリには、CPU負荷の高い関数の例が載っています。128MBで35秒かかった処理が1.5GBでは3秒未満になり、14%安くなった例です。別の例では、128MBで2.4秒の処理が1GBで300msになり、平均費用は変わりませんでした。「メモリを増やすと必ず高くなる」とは言えず、どれだけ縮むかは関数次第です。
Power Tuningの入力と出力を押さえる
AWS Lambda Power Tuningは、AWS Step Functionsで動く状態機械です。Lambda関数のARNを渡すと、複数のメモリ設定でその関数を実際に呼び出し、実行ログを集計して、費用や速度の面で良い設定を示します。
重要なのは、呼び出しがあなたのAWSアカウントの中で本物として走る点です。HTTPリクエストもSDK呼び出しもコールドスタートも、実際に起きます。書き込みを伴う関数をそのまま測ると、本番相当のデータに副作用が出ます。測定用のペイロードと接続先は、測定のために用意してから回します。
実行時の入力は、たとえば次の形です。
{
"lambdaARN": "arn:aws:lambda:ap-northeast-1:123456789012:function:orders-api",
"powerValues": [128, 256, 512, 1024, 2048],
"num": 50,
"payload": { "orderId": "sample-001" },
"strategy": "cost",
"includeOutputResults": true
}ARNとペイロードは例です。主な項目の意味は次のとおりです。
| 項目 | 意味 | 既定・目安 |
|---|---|---|
num | 意味メモリ値ごとの呼び出し回数 | 既定・目安最小5、推奨は10〜100 |
powerValues | 意味試すメモリ値の一覧 | 既定・目安128〜10,240MBの範囲 |
strategy | 意味何を基準に最適値を選ぶか | 既定・目安cost(既定)・speed・balanced |
balancedWeight | 意味balancedでの費用と速度の重み | 既定・目安既定0.5。0でspeed、1でcostと同じ |
discardTopBottom | 意味外れ値として捨てる上下の割合 | 既定・目安既定0.2(上位・下位20%) |
includeOutputResults | 意味メモリ値ごとの平均を出力に含める | 既定・目安既定は含めない |
新しいAWSアカウントは、同時実行数とメモリの上限が低く、メモリは3,008MBまでです。powerValuesにそれを超える値を入れると、測定が通りません。parallelInvocationをtrueにすると呼び出しが同時に走って早く終わりますが、numによってはスロットリングが起きます。
出力のうち読む場所は次の6つです。
results.power: 選ばれた最適メモリresults.cost: その設定での1回当たりの平均費用results.duration: その設定での1回当たりの平均実行時間results.stats: メモリ値ごとの平均費用と平均実行時間(includeOutputResultsを有効にしたときだけ)results.stateMachine.lambdaCost: この測定でLambdaに掛かった費用results.stateMachine.visualization: 結果を見るグラフのURL
可視化URLは、データをURLのハッシュ部分に載せる作りで、集計値はサーバーには送られません。共有するときは、ペイロードに秘密が混ざっていないかを確かめてから貼ります。
測定は人が回し、Claude Codeには結果を渡す
Power Tuningの実行は、Step Functionsの実行開始と、対象関数の実呼び出しを伴います。これをClaude Codeに回させる必然性は薄く、むしろ回数やpowerValuesを取り違えると、課金も副作用も大きくなります。そこで役割を次のように分けます。
見直しの流れ
- 1
人が測定を回す
num・powerValues・ペイロードを決め、Power Tuningを実行します。結果のJSONをtuning/result.jsonに保存します。 - 2
Claude Codeが結果を読む
claude -pに結果を渡し、費用最小と速度優先の候補を構造化して返させます。 - 3
人がメモリ値を決める
候補と費用差を見て、採用する値を人が選びます。
- 4
Claude Codeがテンプレートを直す
選んだ値を
MemorySizeに反映します。デプロイはまだしません。 - 5
人がデプロイし、再測定する
承認してデプロイし、本番相当の負荷で測り直します。
この分担を、権限で担保します。プロジェクトの.claude/settings.jsonには次のように書きます。
{
"permissions": {
"allow": [
"Bash(sam validate *)",
"Bash(sam build *)"
],
"ask": [
"Bash(sam deploy *)",
"Bash(aws stepfunctions start-execution *)"
],
"deny": [
"Bash(aws lambda update-function-configuration *)"
]
}
}評価はdeny、ask、allowの順で、最初に一致したものが結果を決めます。askに一致する呼び出しは、より狭いallowがあっても確認が出ます。
denyに置いたaws lambda update-function-configurationが、今回の肝です。この呼び出しはAWS CLIでメモリを直接変えられる手段で、テンプレートを経由しません。許すと、実環境のメモリだけが変わってテンプレートのMemorySizeと食い違い、次のデプロイで元の値に戻ります。メモリの変更は、必ずテンプレートの差分としてレビューに出す、という線を権限で引いておきます。
Power Tuningには、測定後に最適値を関数へ自動で反映するautoOptimizeがあります。これも実環境を直接書き換える経路なので、IaCで管理している関数では有効にしません。
SAMの検証ループと承認制のデプロイは、Claude CodeでAWS Lambda(SAM)を開発する手順に詳しくあります。aws-serverlessプラグインで設計から検証まで通す場合は、aws-serverlessプラグインの導入と権限が入口になります。
結果をclaude -pに渡して候補を比べる
結果のJSONは、標準入力からclaude -pへ渡せます。出力形式にjsonを選び、--json-schemaでスキーマを付けると、返答はstructured_outputフィールドに入ります。スキーマはファイルに分けておくと、コマンドが長くなりません。
{
"type": "object",
"properties": {
"costOptimal": { "type": "integer" },
"speedOptimal": { "type": "integer" },
"costGapPercent": { "type": "number" },
"note": { "type": "string" }
},
"required": ["costOptimal", "speedOptimal"]
}これをtuning/schema.jsonに置き、次のように呼びます。
cat tuning/result.json | claude --bare -p \
"Power Tuningの結果です。費用最小と速度優先のメモリ値を挙げ、\
後者を選ぶと前者より何%高くなるかをcostGapPercentに入れて" \
--output-format json \
--json-schema "$(cat tuning/schema.json)" \
| jq '.structured_output'いくつか押さえます。
--bareは、フックやCLAUDE.md、MCPサーバーの自動読み込みを省いて、どの環境でも同じ結果にするためのモードです。スクリプト用途で勧められています。サブスクリプションのログインは使わないため、ANTHROPIC_API_KEYを環境変数に設定してから実行します- 標準入力から渡せる量は10MBまでです。
numを大きくしてstatsを含めても、通常はこの上限に届きません - スキーマを満たす出力が得られなかった場合、
structured_outputフィールドは付きません。スクリプトで使う前に、フィールドの有無を確かめます - 返答のJSONには
total_cost_usdも含まれます。見直しのたびに掛かる費用を記録しておけますが、クライアント側の推定値で、実際の請求とは差が出ることがあります
候補の比較に、AIの判断を挟む意味はあります。ただし数字はstatsにすべて入っているので、返ってきた値がstatsの最小費用と一致しているかは、jqで自分でも引いて確かめます。
費用最小と速度優先のどちらを選ぶか
具体例で考えます。次の表は、架空の関数の測定結果です。相対費用は「メモリ(GB)×平均実行時間(ms)」で、単価の絶対値によらず比較できます。
| メモリ | 平均実行時間 | 相対費用(GB・ms) | 費用最小との差 |
|---|---|---|---|
| 128MB | 平均実行時間2,900ms | 相対費用(GB・ms)362.5 | 費用最小との差+3.6% |
| 256MB | 平均実行時間1,400ms | 相対費用(GB・ms)350.0 | 費用最小との差最小 |
| 512MB | 平均実行時間700ms | 相対費用(GB・ms)350.0 | 費用最小との差最小 |
| 1024MB | 平均実行時間420ms | 相対費用(GB・ms)420.0 | 費用最小との差+20% |
| 2048MB | 平均実行時間400ms | 相対費用(GB・ms)800.0 | 費用最小との差+129% |
見るべきは次の3点です。
- 256MBと512MBは費用が同じで、512MBは実行時間が半分になる。費用だけを基準にしても、同額なら速い側を採る理由がある
- 1024MBは512MBより費用が20%上がり、実行時間は700msから420msに縮む。応答時間に厳しい条件があれば、この20%は支払う価値がある
- 2048MBは、実行時間が420msから400msにしか縮まない。費用が約2倍になるだけで、選ぶ理由がない
つまり、費用最小の256MBか512MBに対して、速度優先の1024MBを「+20%で応答が40%短くなる」と比べる、という判断になります。strategyのbalancedとbalancedWeightは、この折り合いを数字で決めたいときに使います。ただし、重みの値そのものは、チームが応答時間と費用のどちらを重く見るかで変わる運用方針です。ツール側に正解はありません。
選び方の基準は、CLAUDE.mdに書いておくとClaude Codeが毎回同じ線で比べます。
## Lambdaメモリの見直しルール
- メモリはPower Tuningの結果から決める。結果が無い関数は推測で変えない
- 費用最小と同額の候補が複数あるときは、実行時間が短い側を採る
- 費用が10%を超えて上がる候補は、応答時間の改善幅を添えて人に聞く
- メモリの変更は template.yaml の MemorySize だけで行い、AWS CLIで直接変えない10%という数字は、例として置いた閾値です。AWSが示す基準ではありません。自分のサービスの応答時間の要件に合わせて決めます。
SAMテンプレートのMemorySizeを直す
採用値が決まったら、Claude Codeにテンプレートを編集させます。編集だけを許す呼び方にして、シェルの権限は渡しません。
claude -p "template.yamlのOrdersFunctionのMemorySizeを512にして。\
他は変えない" --allowedTools "Read,Edit"SAMでは、関数リソースのMemorySizeプロパティがメモリの設定にあたります。template.yamlのこの値を変えてsam deployすれば反映されます。
Resources:
OrdersFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/orders/
MemorySize: 512 # 256から変更。Power Tuningで費用が同額、実行時間が半分差分はgit diffで見ます。MemorySizeの1行だけが変わっていることを確かめてから、sam validateとsam buildをClaude Codeに回させます。Globalsで全関数のメモリを一括指定しているテンプレートでは、関数側にだけ書くと上書きの関係が変わるので、どの関数に効く変更かを差分で確認します。
デプロイはaskなので、確認画面で変更セットの内容を読んでから承認します。承認の画面に映らない設定値の落とし穴は、SAMの記事の「samconfig.tomlは承認画面に映らない」の節にまとめてあります。
本番相当の負荷で確かめ直す
Power Tuningの値は、渡したペイロードの上での平均です。そのまま本番に当てはまるとは限りません。確認は次の3点で行います。
- 代表的なペイロードで測り直す。ペイロードに重みを付けて複数渡す形があり、軽い入力と重い入力が混ざる関数では、重みを付けた混合で測ります
- コールドスタートを含めて見る。
onlyColdStartsを有効にすると、すべての呼び出しがコールドスタートになります。ただし初期化に時間が掛かるので、必要なときだけ使います - 呼び出し先に配慮する。下流のAPIにレート制限があるときは、
sleepBetweenRunsMsで呼び出しの間隔を空けます。並列実行を使うと、この間隔は効きません
デプロイ後は、新しい値を中心にしたpowerValuesで再測定します。たとえば512MBに変えたなら、[256, 384, 512, 768, 1024]のように前後を含めます。測定前と同じnumとペイロードで回し、実行時間と費用が見立てどおりかを比べます。
CloudWatchでは、メモリ使用量が設定値に近づいていないか、実行時間が伸びていないかを継続して見ます。メモリを下げた関数では、使用量が上限に近い状態が続くと、入力が大きい日に失敗する危険があります。これはPower Tuningの測定には現れにくい点です。
AWS Compute Optimizerからも、Lambdaのメモリ推奨を受け取れます。ただし対象はx86_64アーキテクチャーの関数に限られます。Arm向けの関数や、事前に測って根拠を残したいときは、Power Tuningの方が使いやすい場面です。
落とし穴
ペイロードが軽すぎて、本番より低いメモリが「最適」に出る
測定に使った入力が、本番の典型よりも軽い場合、小さいメモリでも速く終わるため、最適値が低めに出ます。本番では重い入力が来た日にだけ実行時間が伸び、タイムアウトに近づきます。重い入力と軽い入力を重み付きで混ぜ、重い側でも想定の実行時間に収まるかを確かめます。
見直しで引っかかる点
numが小さすぎる。最小は5ですが、推奨は10〜100です。外れ値として上下20%が捨てられるので、numが少ないと残る標本が痩せます- 測定中に下流が失敗する。想定内のエラーで測定を止めたくないときは、
allowedExceptionsに扱うエラー名を渡します - 測定がAWSの費用を食う。
results.stateMachine.lambdaCostが、その測定でLambdaに掛かった費用です。メモリ値の数とnumを掛けた回数ぶん呼ばれるので、大きいメモリを大量に回すと無視できません - Claude Codeの返答と
statsが合わない。返答は参考値として扱い、statsの数字を正にします
CIで関数のデプロイごとに自動で測る構成もありますが、メモリの変更をレビュー対象にしたいチームでは、autoOptimizeを使わず、測定だけを自動にして結果を差分として人に見せる形が合います。
まとめ
メモリの見直しは、「実行時間が縮むかどうか」で費用の向きが変わるので、関数ごとに測るしかありません。Power Tuningで測り、費用最小と速度優先の差を数字で並べれば、「あと20%払って応答を4割縮める」のような判断が人にできます。
Claude Codeに任せる範囲は、結果の読み取りとテンプレートの1行の編集までに絞ると安全です。測定の実行、デプロイ、実環境の直接変更は人の側に残します。直した後は、代表的なペイロードで測り直して、見立てが外れていないかを確かめるところまでが一続きの作業です。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。