なぜLambdaにRustなのか
AWS公式が挙げるRustの特徴は以下の4点です。
高いパフォーマンスとして、ネイティブコンパイルにより実行速度がNode.jsやPythonを大幅に上回ります。
メモリ効率については、ガベージコレクションがないため、メモリ使用量が予測可能で少なく済みます。
コンパイル時のコード安全性により、メモリ安全性がコンパイル時に保証され、ランタイムエラーが減少します。
成熟したエコシステムとして、Cargoによるパッケージ管理、豊富なクレート(ライブラリ)が利用可能です。
特にサーバーレス環境では、コールドスタート時間とメモリ課金が直接コストに影響するため、Rustの特性が活きてきます。

Rustランタイムのアーキテクチャ
LambdaにおけるRustの実行モデルは、Node.jsやPythonとは少し異なります。
RustのLambda関数は、ランタイムと関数コードが一体化した単一の実行ファイル(bootstrap)として動作します。Lambda Runtime APIを通じてLambdaサービスと通信し、イベントの取得とレスポンスの送信を行います。
主要なクレートは以下の通りです。
lambda_runtime- Lambdaランタイムのコア機能lambda_http- HTTP API Gateway連携aws_lambda_events- イベント型定義
Cargo Lambdaで開発を始める
AWS公式ブログでは、Cargo Lambdaを使った開発フローが推奨されています。Cargo LambdaはRust用のLambda開発ツールチェーンで、ビルドからデプロイまでをサポートします。
環境構築
まず、Cargo Lambdaをインストールします。
# インストールコマンド(シェル)
cargo install cargo-lambda
# 新規プロジェクト作成
cargo lambda new my-function
前提条件として、Rust 1.70以上が必要です。CDKを使う場合はNode.js 20以上も必要になります。
シンプルなHello World
use lambda_http::{run, service_fn, Body, Error, Request, Response};
use serde::{Deserialize, Serialize};
/// APIからのリクエストボディをパースするための構造体
#[derive(Deserialize)]
struct MyRequest {
name: String,
}
/// クライアントへ返すレスポンスの構造体
#[derive(Serialize)]
struct MyResponse {
message: String,
}
/// メインのロジックを担うハンドラ関数
async fn function_handler(event: Request) -> Result<Response<Body>, Error> {
// 1. リクエストボディの取り出しとパース
let body = event.body();
let s = std::str::from_utf8(body).unwrap_or("{}");
let req: MyRequest = serde_json::from_str(s).map_err(|_| "Invalid JSON")?;
// 2. ビジネスロジックの実行
let greeting = format!("Hello, {}! Welcome to Rust on AWS Lambda.", req.name);
let resp_data = MyResponse { message: greeting };
// 3. HTTPレスポンスの構築
let resp = Response::builder()
.status(200)
.header("content-type", "application/json")
.body(serde_json::to_string(&resp_data)?.into())
.map_err(Box::new)?;
Ok(resp)
}
#[tokio::main]
async fn main() -> Result<(), Error> {
// トレーシング(ログ)の初期化
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.with_target(false)
.without_time()
.init();
// ランタイムの起動
run(service_fn(function_handler)).await
}実行環境ライフサイクルとパフォーマンス
Lambdaの実行環境には3つのフェーズがあります。
Initフェーズでは、ランタイムのブートストラップと関数の静的コード実行が行われます。このフェーズは最大10秒と定められています。Rustの場合、バイナリの起動が非常に高速なため、このフェーズを短縮できます。
Invokeフェーズでは、Runtime APIからイベントを取得してハンドラ関数を実行します。
Shutdownフェーズでは、実行環境の終了処理が行われます。
コールドスタートの実測値
Rustの最大の強みはコールドスタート時間です。
AWS公式のパフォーマンス測定によると、シンプルなHTTP関数でコールドスタートが10ms以下、ウォームスタートは数ms程度という結果が報告されています。
これはNode.jsの100-200ms、Pythonの200-300ms、Javaの1-3秒と比較すると劇的な差です。
AWS CDKとの連携
Rustの関数をCDKでデプロイする場合、RustFunction コンストラクトが利用できます。
// CDKでのRust Lambda定義イメージ
import { RustFunction } from '@aws-cdk/aws-lambda-rust-alpha';
const rustFn = new RustFunction(this, 'MyRustFunction', {
manifestPath: 'path/to/Cargo.toml',
bundling: {
cargoLambdaFlags: ['--release'],
},
});CDKがビルドプロセスを自動化してくれるため、CI/CDパイプラインへの組み込みもスムーズです。
適したユースケース
Rustが特に活きるユースケースを整理します。
レイテンシ重視のAPIでは、ユーザー向けAPIでミリ秒単位のレスポンスが求められる場合に最適です。コールドスタートが短いため、スパイクトラフィック時も安定します。
高頻度バッチ処理として、SQSやKinesisからのイベント処理で大量のメッセージを効率的に処理できます。
リソース制約環境では、メモリを128MBに絞ってコスト最適化したい場合に有効です。Rustなら128MBでも十分動作します。
クリティカルなワークロードとして、メモリ安全性がコンパイル時に保証されるため、金融系など信頼性が求められる場面に適しています。
私の見解
正直、「Lambda全部Rustにすべき」とは思いません。開発速度とメンテナンス性を考えると、多くのケースではNode.jsやPythonで十分です。
しかし、以下のようなケースではRustの採用を検討する価値があります。
- コールドスタートが許容できないリアルタイム処理
- メモリ128MBでコストを極限まで削減したい
- 長期運用でランタイムエラーを最小化したい
- すでにRustエコシステムに精通したチームがいる
今回のGA化により、Rustは「趣味」から「選択肢」になりました。適材適所で使い分けることで、サーバーレスアーキテクチャの幅が広がります。
まとめ
AWS LambdaでのRust正式サポートにより、以下が可能になりました。
- コールドスタート10ms以下の超高速起動
- メモリ効率の良さによるコスト最適化
- コンパイル時のメモリ安全性保証
- Cargo Lambdaによる開発体験の向上
- 全AWSリージョン(GovCloud、中国含む)で利用可能
パフォーマンスが最優先のワークロードには、いよいよRustが本命の選択肢になったかなと感じています。














