[アップデート] AWS Lambda での Rust の利用が一般提供(GA)になりました

[アップデート] AWS Lambda での Rust の利用が一般提供(GA)になりました

2025.11.18

こんにちは、クラウド事業本部 コンサルティング部の荒平(@eiraces)です。

2025年11月14日、以下のアップデート AWS Lambda adds support for Rust が舞い込んできました。
これまでは試験的なサポートであり、本番環境のワークロードでは利用しないように周知されていましたが、これからはAWS Support、あるいはLambdaのSLAに則る形となります。

https://aws.amazon.com/jp/about-aws/whats-new/2025/11/aws-lambda-rust/

このアップデートは?

筆者は Rust のエキスパートではないのですが、開発者からの人気が結構あるので存在は良く知っていました。
DevelopersIOにも、AWS Lambda で Rust を動かしてみる検証記事が何本か出ています。

https://dev.classmethod.jp/articles/s3-select-python-lambda-call-by-rust-lambda/

https://dev.classmethod.jp/articles/rust-lambda-cdk/

https://dev.classmethod.jp/articles/aws-lambda-rust-m1/

Lambdaのランタイムでよく選ばれるのが Pythonですが、強力な型付けを必要とする場合にやはりPythonが向いていないシーンがありました。
その需要に応える形で Node.js 以外の選択肢として Rust が登場したのはありがたいですね。

Rust の実行速度は概ねC, C++に匹敵するという日経クロステック様の記述を見つけたので、Lambda 上でサンプルコードを動かして確認してみたいと思います。

Rust on Lambda を動かしてみる

では早速やっていきましょう。

ローカルで Rust プロジェクトをビルドするための環境を整備します。
Cargoは Rust のパッケージマネージャーで、AWS Lambdaと連携するために cargo-lambdaを利用します。

## Rust 環境がない場合、インストールしておく (Mac用)
brew install rust
brew install cargo
brew install rustup

## cargo-lambda のインストール
## https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html
cargo install cargo-lambda
cargo lambda new <関数名>

今回利用するサンプルコードはフィボナッチ数列の再帰計算をするコードをClaudeに作らせました。
初期化後のフォルダに src/main.rs があるので、置き換えておきます。

main.rs
use lambda_runtime::{service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Instant;

#[derive(Deserialize)]
struct Request {
    #[serde(default = "default_fib_n")]
    fib_n: u32,
    items: Option<Vec<Item>>,
}

fn default_fib_n() -> u32 {
    35
}

#[derive(Deserialize, Serialize, Clone)]
struct Item {
    id: u32,
    value: u64,
    category: String,
}

#[derive(Serialize)]
struct Response {
    #[serde(rename = "statusCode")]
    status_code: u16,
    body: ResponseBody,
}

#[derive(Serialize)]
struct ResponseBody {
    fibonacci: FibonacciResult,
    json_processing: JsonProcessingResult,
    total_duration_ms: f64,
    runtime: String,
}

#[derive(Serialize)]
struct FibonacciResult {
    n: u32,
    result: u64,
    duration_ms: f64,
}

#[derive(Serialize)]
struct JsonProcessingResult {
    items_count: usize,
    iterations: u32,
    duration_ms: f64,
    result: ProcessedData,
}

#[derive(Serialize)]
struct ProcessedData {
    total: u64,
    count: usize,
    average: f64,
    categories: HashMap<String, u32>,
}

fn fibonacci(n: u32) -> u64 {
    if n <= 1 {
        n as u64
    } else {
        fibonacci(n - 1) + fibonacci(n - 2)
    }
}

fn process_data(items: &[Item]) -> ProcessedData {
    let mut total: u64 = 0;
    let mut categories: HashMap<String, u32> = HashMap::new();

    for item in items {
        total += item.value;
        *categories.entry(item.category.clone()).or_insert(0) += 1;
    }

    ProcessedData {
        total,
        count: items.len(),
        average: if items.is_empty() {
            0.0
        } else {
            total as f64 / items.len() as f64
        },
        categories,
    }
}

async fn handler(event: LambdaEvent<Request>) -> Result<Response, Error> {
    let start_time = Instant::now();
    let request = event.payload;

    // 1. CPU負荷: フィボナッチ計算
    let fib_start = Instant::now();
    let fib_result = fibonacci(request.fib_n);
    let fib_duration = fib_start.elapsed().as_secs_f64() * 1000.0;

    // 2. JSON処理: データ集計
    let items = request.items.unwrap_or_else(|| {
        (0..1000)
            .map(|i| Item {
                id: i,
                value: (i as u64) * 10,
                category: format!("cat_{}", i % 5),
            })
            .collect()
    });

    let json_start = Instant::now();
    let mut deserialized = items.clone();

    // シリアライズ/デシリアライズを複数回
    for _ in 0..100 {
        let serialized = serde_json::to_string(&deserialized)?;
        deserialized = serde_json::from_str(&serialized)?;
    }

    let processed = process_data(&deserialized);
    let json_duration = json_start.elapsed().as_secs_f64() * 1000.0;

    let total_duration = start_time.elapsed().as_secs_f64() * 1000.0;

    Ok(Response {
        status_code: 200,
        body: ResponseBody {
            fibonacci: FibonacciResult {
                n: request.fib_n,
                result: fib_result,
                duration_ms: (fib_duration * 100.0).round() / 100.0,
            },
            json_processing: JsonProcessingResult {
                items_count: deserialized.len(),
                iterations: 100,
                duration_ms: (json_duration * 100.0).round() / 100.0,
                result: processed,
            },
            total_duration_ms: (total_duration * 100.0).round() / 100.0,
            runtime: "rust".to_string(),
        },
    })
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}

初期設定と配置が終わったら、次はビルドをしてみます。Apple SiliconのMacではそのまま動作はしないようで、最終的にはリンカの設定修正などを行いました。
リンカ(Linker)はコンパイル後のオブジェクトファイルを実行可能形式にまとめるツールで、C言語でいうgcc からコンパイラを除いた部分というざっくり理解です。

Mac環境でない場合はビルドコマンドのみでOKです。

## rustupを優先するようにする
export PATH="$HOME/.cargo/bin:$PATH"

## リンカの設定を修正
cat > .cargo/config.toml << 'EOF'
[target.x86_64-unknown-linux-musl]
linker = "rust-lld"
EOF

## ビルドを実行
cargo lambda build --release

**Finished**release profile [optimized] target(s) in 12.39s のような文字が出力されるとビルド成功です。

続いて、Lambdaにデプロイしていきます。

cd target/x86_64-unknown-linux-musl/release
cp comparison-rust bootstrap
zip lambda.zip bootstrap

aws lambda create-function \
  --function-name rust-benchmark \
  --runtime provided.al2023 \
  --handler bootstrap \
  --role arn:aws:iam::000000000000:role/<LambdaRoleName> \
  --zip-file fileb://lambda.zip \
  --memory-size 1024 \
  --timeout 60

無事にデプロイできたら、動かしてみましょう。
フィボナッチ関数に35を渡すことで、約2930万回の計算処理が発生します。

aws lambda invoke \
  --function-name rust-benchmark \
  --payload '{"fib_n": 35}' \
  --cli-binary-format raw-in-base64-out \
  response.json && cat response.json | jq .

StatusCode が200になっていれば、正常に動作しています。

{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
{
  "statusCode": 200,
  "body": {
    "fibonacci": {
      "n": 35,
      "result": 9227465,
      "duration_ms": 48.19
    },
    "json_processing": {
      "items_count": 1000,
      "iterations": 100,
      "duration_ms": 104.04,
      "result": {
        "total": 4995000,
        "count": 1000,
        "average": 4995.0,
        "categories": {
          "cat_0": 200,
          "cat_1": 200,
          "cat_3": 200,
          "cat_4": 200,
          "cat_2": 200
        }
      }
    },
    "total_duration_ms": 152.5,
    "runtime": "rust"
  }
}

合計の処理時間は 152.5 ms という結果になりました。
速い…のか?と分からなくなったので、Pythonで同様の処理を実施してみることにしました。

Python でフィボナッチ数列を再帰計算するコードは以下の通りです。

main.py
import json
import time
from typing import Any

def fibonacci(n: int) -> int:
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

def process_data(items: list[dict]) -> dict:
    """データ処理シミュレーション"""
    total = 0
    categories = {}

    for item in items:
        total += item.get("value", 0)
        cat = item.get("category", "unknown")
        categories[cat] = categories.get(cat, 0) + 1

    return {
        "total": total,
        "count": len(items),
        "average": total / len(items) if items else 0,
        "categories": categories
    }

def lambda_handler(event: dict, context: Any) -> dict:
    start_time = time.perf_counter()

    # 1. CPU負荷: フィボナッチ計算
    fib_n = event.get("fib_n", 35)
    fib_start = time.perf_counter()
    fib_result = fibonacci(fib_n)
    fib_duration = (time.perf_counter() - fib_start) * 1000

    # 2. JSON処理: データ集計
    items = event.get("items", [
        {"id": i, "value": i * 10, "category": f"cat_{i % 5}"}
        for i in range(1000)
    ])

    json_start = time.perf_counter()
    # シリアライズ/デシリアライズを複数回
    for _ in range(100):
        serialized = json.dumps(items)
        deserialized = json.loads(serialized)

    processed = process_data(deserialized)
    json_duration = (time.perf_counter() - json_start) * 1000

    total_duration = (time.perf_counter() - start_time) * 1000

    return {
        "statusCode": 200,
        "body": {
            "fibonacci": {
                "n": fib_n,
                "result": fib_result,
                "duration_ms": round(fib_duration, 2)
            },
            "json_processing": {
                "items_count": len(items),
                "iterations": 100,
                "duration_ms": round(json_duration, 2),
                "result": processed
            },
            "total_duration_ms": round(total_duration, 2),
            "runtime": "python3.13"
        }
    }

Rust と同様にデプロイ&実行します。

aws lambda create-function \
  --function-name python-benchmark \
  --runtime python3.13 \
  --handler lambda_function.lambda_handler \
  --role arn:aws:iam::000000000000:role/<LambdaRoleName> \
  --zip-file fileb://lambda.zip \
  --memory-size 1024 \
  --timeout 60

aws lambda invoke \
  --function-name python-benchmark \
  --payload '{"fib_n": 35}' \
  --cli-binary-format raw-in-base64-out \
  response.json && cat response.json | jq .

以下のような結果になりました。

{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
{
  "statusCode": 200,
  "body": {
    "fibonacci": {
      "n": 35,
      "result": 9227465,
      "duration_ms": 2956.26
    },
    "json_processing": {
      "items_count": 1000,
      "iterations": 100,
      "duration_ms": 256.05,
      "result": {
        "total": 4995000,
        "count": 1000,
        "average": 4995.0,
        "categories": {
          "cat_0": 200,
          "cat_1": 200,
          "cat_2": 200,
          "cat_3": 200,
          "cat_4": 200
        }
      }
    },
    "total_duration_ms": 3213.33,
    "runtime": "python3.13"
  }
}

合計処理時間は 3213.33ms でしたので、今回の検証では Rust が Python より約20倍高速 という結果になりました。
(※ 処理内容にもよるため、若干恣意的な結果です。今回は両者の計算量を敢えて O(2^n) にして比較しています)

Python側はPyPyにすることで処理時間の差は詰まりそうですが、パッケージサイズが大きくなるなど別のデメリットが出そうです。

おわりに

Lambdaが正式に Rust をサポートしたことで、パフォーマンスを求める処理などはこちらで作成することもありそうです。
今回は検証できていませんが、コールドスタートが高速であることも特徴の一つなので流行るかもしれませんね。

私の環境がMacだったために最初少し躓きましたが、Rust が面白そうなのでちょこちょこ触ってみたいと思います。

このエントリが誰かの助けになれば幸いです。
それでは、クラウド事業本部 コンサルティング部の荒平がお送りしました!

参考

https://docs.aws.amazon.com/lambda/latest/dg/rust-package.html

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/rust-handler.html

https://dev.classmethod.jp/articles/aws-lambda-rust-m1/

この記事をシェアする

FacebookHatena blogX

関連記事