大きなデータを、キーで渡す — Lambda間の大容量ペイロード受け渡し設計
同期呼び出しにもペイロード上限がある。大きな入力を安全に渡すために、データはインメモリに退避し、鍵だけを手渡す。
PROBLEMペイロード上限という物理的な壁
サーバーレス基盤で機能を関数(Lambda)へ分解していくと、ある関数が別の関数を呼び出し、処理結果や入力オブジェクトを引き渡す場面が頻繁に生まれる。ここで見落とされがちなのが、関数呼び出しには同期・非同期を問わずペイロードサイズの上限が存在するという事実だ。同期呼び出しでは数MB規模、非同期呼び出しではさらに小さい上限が課される。
問題は、業務ロジックが扱うオブジェクトが必ずしも小さくない点にある。注文全体、明細の一括データ、算定対象の顧客集合といった「まとまった入力」を丸ごと引数に載せると、上限を静かに超えて呼び出しが失敗する。しかも失敗は入力データのサイズ次第で顕在化するため、開発環境の小さなデータでは通り、本番の大きなデータで初めて落ちる、という厄介な形で現れる。
- ペイロードが上限を超えると呼び出し自体がエラーになる。
- 大きな入力をそのまま渡すと、呼び出しログや実行ログにデータ本体が展開され、ログが肥大する。
- 機微データがログや監査証跡に残り続けるリスクが生じる。
SOLUTIONデータは退避し、鍵だけを手渡す
解決の発想はシンプルだ。大きなデータそのものを運ぶのをやめ、データはインメモリストア(Redis/Valkey)に一時保存し、その保存場所を指す「キー」だけを呼び出しに載せる。物理的な引っ越しではなく、荷物を預けてクロークの番号札だけを渡すイメージに近い。
送信側は、渡したい大きな params をシリアライズしてインメモリストアへ TTL 付きで保存し、一意なキー(UUID)を発行する。呼び出しのペイロードには { redisKey: key } のような軽量なオブジェクトだけを載せる。受信側は受け取ったキーでストアを引き、データ本体を取り出して処理を進める。ペイロードは常に数十バイトに収まり、入力データがどれだけ巨大でも上限に触れない。
BENEFIT上限回避だけではない副次効果
この設計の直接的な利点はペイロード上限の回避だが、恩恵はそれにとどまらない。呼び出しに乗るのはキーだけなので、呼び出しログや実行ログにデータ本体が展開されず、ログの肥大とノイズが抑えられる。副次的に、機微データがログへ漏れ出す経路も一つ減る。
- ペイロード上限の回避:入力サイズに依存せず呼び出しが安定する。
- ログ肥大の回避:ログに残るのはキーのみ。
- 疎結合:送信側と受信側はキーの規約だけで結びつき、データ構造の変更に強い。
- 自動掃除:TTL により、取り出されなかったデータも自然に消える。ゴミ掃除の運用が要らない。
CODE擬似コードで見る受け渡し
// 送信側:大きな params をストアへ退避し、キーを発行 const key = crypto.randomUUID(); await store.setEx(key, TTL_SECONDS, JSON.stringify(params)); // 呼び出しにはキーだけを載せる(ペイロードは軽量) const payload = { redisKey: key }; await invoke("downstream-fn", payload); // 受信側:キーで本体を取り出す const raw = await store.get(event.redisKey); if (raw === null) { // TTL切れ / ストア障害:再取得や再実行のフォールバックへ throw new Error("payload expired or missing"); } const params = JSON.parse(raw); // params.items.length などをそのまま処理できる
TRADE-OFF番号札を渡すことの代償
データを間接化する以上、代償もある。第一に、ストアが単一障害点になり得る。ストア障害や TTL 切れの間はキーを引いても本体が取れず、受信側は「データが無い」状態に直面する。TTL は処理完了までの最大時間より十分に長く取り、取れなかった場合の再取得・再実行・エラー返却といったフォールバックを必ず用意する。
第二に、キーの一意性。衝突すれば他の呼び出しのデータを上書きしかねないため、UUID など衝突しない生成方式を用いる。第三に、機微データの扱い。ストアに実データが載る以上、TTL を短く保つ、保存時にマスキングや暗号化を施す、といった配慮が要る。運ぶ経路が短くなっても、預けた荷物の中身の管理責任は消えない。この間接化のコストを払う価値があるのは、あくまで入力が大きくなり得る経路に限られる。小さなペイロードで完結する呼び出しにまで適用すると、ストアへの往復が無駄なレイテンシと依存を生むだけになる。
関数間で大きな入力を運ぶときは、データそのものではなくインメモリストアの「キー」を渡す。ペイロード上限とログ肥大を同時に回避でき、TTL が後片付けまで担う。代償はストア障害・TTL切れ・機微データ管理であり、フォールバックと短いTTLで抑え、適用は大きくなり得る経路に絞る。