Lambda Managed Instances + Rust:实测 Graviton4 性能对比¶
Lab 信息
- 难度: ⭐⭐ 中级
- 预估时间: 30 分钟
- 预估费用: ~$1-2(3x m8g.xlarge 运行约 10 分钟)
- Region: us-east-1
- 最后验证: 2026-03-19
背景¶
Lambda Managed Instances 是 AWS 在 2025 年推出的 Lambda 新计算模式 — 函数跑在你账号里的 EC2 实例上,但 AWS 管理实例生命周期、路由、负载均衡和扩缩容。2026 年 3 月 13 日,这个模式新增了 Rust 支持,开启了 Rust 多请求并行处理 能力。
核心卖点:Lambda 的开发体验 + EC2 的硬件选择和定价优势 + Rust 的极致性能。
前置条件¶
- AWS 账号(需要 Lambda、EC2、IAM 权限)
- Rust 1.84.0+(
rustup target add aarch64-unknown-linux-gnu) gcc-aarch64-linux-gnu(交叉编译)
核心概念¶
Lambda Managed Instances vs 标准 Lambda¶
| 维度 | 标准 Lambda | Managed Instances |
|---|---|---|
| 并发模型 | 1 请求 / 执行环境 | 多请求并行 / 执行环境 |
| 底层硬件 | 共享 Lambda 集群 | 你的 EC2 实例(Graviton4 等) |
| 隔离 | Firecracker microVM | EC2 Nitro 容器 |
| 定价 | 按请求时长 | EC2 价格 + 15% 管理费 |
| 扩缩容 | 冷启动触发,可缩到 0 | CPU 利用率触发,最小 3 实例 |
| 冷启动 | 有 | 无(实例预热) |
架构¶
Capacity Provider
├── m8g.xlarge (AZ-a)
│ └── 执行环境
│ ├── Worker 1 → request A
│ ├── Worker 2 → request B
│ └── Worker N → request N (默认 8/vCPU)
├── m8g.xlarge (AZ-b)
└── m8g.xlarge (AZ-c)
Rust 并行模式¶
// Cargo.toml
lambda_runtime = { version = "1", features = ["concurrency-tokio"] }
// main.rs - 使用 run_concurrent 替代 run
run_concurrent(service_fn(handler)).await
- 默认 8 并发 / vCPU,可配置
PerExecutionEnvironmentMaxConcurrency - Handler 必须
Clone + Send(线程安全) - 共享状态用
Arc,AWS SDK 客户端可直接 clone
动手实践¶
Step 1: 创建 Rust Lambda 项目¶
Cargo.toml:
[dependencies]
lambda_runtime = { version = "1", features = ["concurrency-tokio"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = "0.3"
src/main.rs:
use lambda_runtime::{run_concurrent, service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};
use std::time::Instant;
#[derive(Deserialize)]
struct Request {
#[serde(default)]
action: String,
#[serde(default)]
sleep_ms: u64,
}
#[derive(Serialize)]
struct Response {
message: String,
request_id: String,
elapsed_ms: u128,
}
async fn handler(event: LambdaEvent<Request>) -> Result<Response, Error> {
let start = Instant::now();
let message = match event.payload.action.as_str() {
"sleep" => {
tokio::time::sleep(std::time::Duration::from_millis(
event.payload.sleep_ms.max(1)
)).await;
format!("Slept for {}ms", event.payload.sleep_ms)
}
"cpu" => {
let result = fib(35);
format!("fib(35) = {}", result)
}
_ => "Hello from Rust MI!".into(),
};
Ok(Response {
message,
request_id: event.context.request_id,
elapsed_ms: start.elapsed().as_millis(),
})
}
fn fib(n: u64) -> u64 {
if n <= 1 { return n; }
fib(n - 1) + fib(n - 2)
}
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing_subscriber::fmt().json().init();
run_concurrent(service_fn(handler)).await
}
Step 2: 交叉编译为 arm64¶
rustup target add aarch64-unknown-linux-gnu
# .cargo/config.toml
mkdir -p .cargo && cat > .cargo/config.toml << 'EOF'
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
EOF
cargo build --release --target aarch64-unknown-linux-gnu
cp target/aarch64-unknown-linux-gnu/release/rust-mi-lab bootstrap
zip lambda.zip bootstrap
二进制仅 2.7MB(压缩后 984KB)。
Step 3: 创建 Capacity Provider¶
# 创建 Operator IAM Role
aws iam create-role --role-name LambdaMIOperatorRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# 创建 Capacity Provider
aws lambda create-capacity-provider \
--capacity-provider-name my-rust-cp \
--vpc-config 'SubnetIds=subnet-xxx,subnet-yyy,subnet-zzz,SecurityGroupIds=sg-xxx' \
--permissions-config 'CapacityProviderOperatorRoleArn=arn:aws:iam::ACCOUNT:role/LambdaMIOperatorRole' \
--instance-requirements 'Architectures=arm64' \
--capacity-provider-scaling-config 'ScalingMode=Auto'
Step 4: 创建 Lambda 函数(关联 Capacity Provider)¶
aws lambda create-function \
--function-name rust-mi-lab \
--runtime provided.al2023 \
--architectures arm64 \
--handler bootstrap \
--role 'arn:aws:iam::ACCOUNT:role/LambdaMIExecRole' \
--zip-file fileb://lambda.zip \
--timeout 30 \
--memory-size 2048 \
--capacity-provider-config '{
"LambdaManagedInstancesCapacityProviderConfig": {
"CapacityProviderArn": "arn:aws:lambda:us-east-1:ACCOUNT:capacity-provider:my-rust-cp",
"PerExecutionEnvironmentMaxConcurrency": 16
}
}'
内存最小 2048MB
Managed Instance 函数的 memory-size 最小 2048MB,不能像标准 Lambda 那样设 128MB。
Step 5: 发布版本并等待就绪¶
aws lambda publish-version --function-name rust-mi-lab --description 'v1'
# 等待约 2 分钟,EC2 实例启动 + 执行环境初始化
发布后,AWS 自动启动 3 个 EC2 实例(跨 AZ),我们的测试中自动选择了 m8g.xlarge(Graviton4, 4 vCPU, 16GB)。
Step 6: 调用测试¶
aws lambda invoke --function-name rust-mi-lab --qualifier 1 \
--payload '{"action": "cpu"}' \
--cli-binary-format raw-in-base64-out /dev/stdout
实测数据¶
性能对比:Standard Lambda vs Managed Instance¶
| 测试 | Standard Lambda (256MB) | MI (m8g.xlarge) | 差距 |
|---|---|---|---|
| fib(35) | 197ms | 17ms | 11.6x 更快 |
| hello (no-op) | < 1ms | < 1ms | 相当 |
| sleep(100ms) | 101ms | 101ms | 相当(IO bound) |
CPU 密集型任务差距显著
Standard Lambda 256MB ≈ 0.17 vCPU。Managed Instance m8g.xlarge = 4 vCPU(Graviton4)。 CPU 密集型任务差距 11.6x,这是硬件能力的直接体现。
并发处理¶
| 测试 | 描述 | 每请求耗时 | 总 wall time |
|---|---|---|---|
| 10x sleep(200ms) | IO 并发 | ~201ms | 1.9s |
| 5x fib(35) | CPU 并发 | ~17ms | 1.4s |
基础设施¶
| 指标 | 数值 |
|---|---|
| 自动选择实例 | m8g.xlarge (Graviton4) |
| 实例数量 | 3(跨 AZ) |
| 版本发布到可用 | ~2 分钟 |
| 并发度配置 | 16 / 执行环境 |
| 二进制大小 | 2.7MB (984KB zipped) |
踩坑记录¶
必须在 create-function 时指定 Capacity Provider
不能先创建标准 Lambda 再 update 为 Managed Instance。必须在 create-function 时通过 --capacity-provider-config 指定。
Memory 最小 2048MB
标准 Lambda 最小 128MB,Managed Instance 最小 2048MB。
$LATEST 不可调用
MI 函数的 $LATEST 状态为 ActiveNonInvocable。必须 publish-version 创建版本号后才能调用。
3 个 EC2 实例持续运行
发布版本后,默认启动 3 个 EC2 实例(AZ 冗余),即使没有流量也不会缩到 0。这是成本需要注意的地方。
交叉编译注意
macOS/x86 开发机交叉编译到 arm64 需要 aarch64-linux-gnu-gcc linker。在 .cargo/config.toml 中配置。
费用明细¶
| 资源 | 规格 | 费用 |
|---|---|---|
| 3x m8g.xlarge | ~10 分钟运行 | ~$0.15 |
| 15% 管理费 | 在 EC2 价格之上 | ~$0.02 |
| Lambda 调用 | 测试请求 | < $0.01 |
| 合计 | ~$0.20 |
生产环境定价优势
EC2 Savings Plans 和 Reserved Instances 可以应用到 Managed Instance 的 EC2 部分(不含 15% 管理费),对稳定负载有显著成本优势。
清理资源¶
# 删除函数(会释放版本与 capacity provider 的关联)
aws lambda delete-function --function-name rust-mi-lab
# 等待约 30 秒后删除 capacity provider(触发 EC2 实例终止)
sleep 30
aws lambda delete-capacity-provider --capacity-provider-name my-rust-cp
# 删除 IAM Roles
aws iam detach-role-policy --role-name LambdaMIOperatorRole --policy-arn ...
aws iam delete-role --role-name LambdaMIOperatorRole
aws iam delete-role --role-name LambdaMIExecRole
务必删除 Capacity Provider
Capacity Provider 不删除 = 3 个 EC2 实例持续运行计费!
结论与建议¶
适合场景¶
- 高吞吐 API:Rust + 多请求并行 + Graviton4,极致性价比
- 稳定负载:可用 Savings Plans / RI 降低成本
- CPU 密集型:视频编解码、图像处理、ML 推理
- 低延迟要求:无冷启动
不适合场景¶
- 突发/稀疏流量:不缩到 0 = 空闲也付费
- 简单函数:如果 256MB Lambda 够用,没必要上 MI
- 快速原型:标准 Lambda 上手更快
建议¶
- 让 AWS 选实例类型 — 除非有特殊需求,
Architectures=arm64即可 - 用 Rust 的多并发 —
concurrency-tokiofeature +run_concurrent(),这是 MI + Rust 的核心价值 - 共享状态用 Arc — /tmp 目录跨并发共享,注意文件名冲突
- 监控 EC2 实例 — 通过
aws:lambda:capacity-providertag 识别