11 - 边缘计算
11 - 边缘计算
边缘计算是 WebAssembly 增长最快的非浏览器应用场景——快速启动、沙箱安全、跨平台。
11.1 为什么 Wasm 适合边缘计算?
| 特性 | Wasm | Docker 容器 | 原生函数 |
|---|---|---|---|
| 冷启动时间 | < 1ms | 100ms - 数秒 | < 1ms |
| 内存占用 | KB 级 | MB 级 | KB 级 |
| 安全沙箱 | ✅ 内建 | ⚠️ 需配置 | ❌ 无 |
| 跨平台 | ✅ | ⚠️ 依赖架构 | ❌ |
| 语言无关 | ✅ | ✅ | ❌ |
| 二进制大小 | KB - MB | 数十 MB | KB - MB |
边缘计算的优势
用户 ──────► 边缘节点 ──────► 源站
│ │
│ <10ms延迟 │ 100-500ms 延迟
│ │
└──────────────┘
边缘节点部署在离用户最近的网络节点
11.2 Cloudflare Workers
Cloudflare Workers 是最早大规模支持 Wasm 的边缘计算平台,全球有 300+ 节点。
快速开始
# 使用 Wrangler CLI
npm create cloudflare@latest my-worker
cd my-worker
# 选择 "Hello World" 模板
# wrangler.toml 中配置 Wasm
项目配置
# wrangler.toml
name = "my-wasm-worker"
main = "src/index.js"
compatibility_date = "2024-01-01"
# 方式 1:直接引用 Wasm 文件
[[wasm_modules]]
MODULE_WASM = "wasm/module.wasm"
# 方式 2:通过构建脚本
[build]
command = "cargo install wasm-pack && wasm-pack build --target web"
Rust + wasm-bindgen 示例
// src/lib.rs
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn process_request(url: &str, body: &str) -> String {
// 在边缘节点执行的逻辑
let hash = compute_hash(body);
let timestamp = js_sys::Date::now();
format!(
r#"{{"url":"{}","hash":"{}","timestamp":{},"processed_at":"edge"}}"#,
url, hash, timestamp
)
}
fn compute_hash(data: &str) -> String {
// 使用 blake3 等轻量哈希
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
format!("{:x}", hasher.finish())
}
// src/index.js — Worker 入口
import { process_request } from '../pkg/my_wasm.js';
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const body = await request.text();
const result = process_request(url.pathname, body);
return new Response(result, {
headers: { 'Content-Type': 'application/json' }
});
}
};
纯 Rust Worker
// 使用 worker-rs crate
use worker::*;
#[event(fetch)]
async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
let router = Router::new();
router
.get_async("/api/:name", |_req, ctx| async move {
let name = ctx.param("name").unwrap();
Response::ok(format!("Hello, {}!", name))
})
.post_async("/api/process", |mut req, _ctx| async move {
let body = req.text().await?;
let result = process_data(&body);
Response::ok(result)
})
.run(req, env)
.await
}
KV 存储与 D1 数据库
use worker::*;
#[event(fetch)]
async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
// KV 存储
let kv = env.kv("MY_KV")?;
kv.put("key", "value")?.execute().await?;
let value = kv.get("key").text().await?;
// D1 数据库
let db = env.d1("MY_DB")?;
let stmt = db.prepare("SELECT * FROM users WHERE id = ?");
let row = stmt.bind(&[1.into()])?.first(None).await?;
Response::ok(format!("KV: {}, DB: {:?}", value, row))
}
11.3 Fastly Compute
Fastly Compute 是另一个成熟的 Wasm 边缘计算平台,使用 Wasmtime 运行时。
快速开始
# 安装 Fastly CLI
brew install fastly/tap/fastly
# 创建项目
fastly compute init --language=rust
# 构建
fastly compute build
# 本地测试
fastly compute serve
# 部署
fastly compute deploy
Rust 示例
use fastly::http::{Method, StatusCode};
use fastly::{Error, Request, Response};
#[fastly::main]
fn main(req: Request) -> Result<Response, Error> {
match (req.get_method(), req.get_path()) {
(&Method::GET, "/") => {
Ok(Response::from_status(StatusCode::OK)
.with_body_text_plain("Hello from Fastly Compute!"))
}
(&Method::POST, "/api/transform") => {
let body = req.into_body_str();
let transformed = transform_data(&body);
Ok(Response::from_status(StatusCode::OK)
.with_body_text_html(&transformed)
.with_header("Content-Type", "application/json"))
}
_ => Ok(Response::from_status(StatusCode::NOT_FOUND))
}
}
fn transform_data(input: &str) -> String {
// 边缘数据转换逻辑
format!(r#"{{"input_length":{},"transformed_at":"edge"}}"#, input.len())
}
Fastly 特性
| 特性 | 说明 |
|---|---|
| Geolocation | 根据 IP 获取地理位置 |
| KV Store | 全球分布式键值存储 |
| Config Store | 配置管理 |
| Secret Store | 敏感信息管理 |
| Backend API | 代理到后端服务 |
| Edge Dictionary | 低延迟字典 |
11.4 WasmEdge
WasmEdge 是一个高性能的 Wasm 运行时,特别适合边缘设备和 AI 推理场景。
安装
# 一键安装
curl -sSf https://raw.githubusercontent.com/nicedoc/nicedoc.io/master/install.sh | bash
# 或使用包管理器
brew install wasmedge
AI 推理集成
// 使用 WasmEdge 的 TensorFlow Lite 扩展
use wasmedge_tensorflow_interface::*;
fn classify_image(image_data: &[u8]) -> Vec<(String, f32)> {
let model_data = include_bytes!("model.tflite");
let labels = include_str!("labels.txt");
let mut session = TensorflowSession::new(
model_data,
TensorflowModelType::TensorflowLite,
TensorflowTarget::CPU,
);
session.add_input("input", image_data)
.run()
.expect("Inference failed");
let output = session.get_output("output");
// 解析输出...
vec![]
}
命令行运行
# 运行 WASI 应用
wasmedge --dir .:. app.wasm
# 启用 TensorFlow 支持
wasmedge-tensorflow-lite app.wasm
# 启用网络支持
wasmedge --dir .:. --nn-preload default:tensorflowlite:model.tflite app.wasm
11.5 Deno Deploy
// Deno Deploy 原生支持 Wasm
const wasmModule = await WebAssembly.compile(
await Deno.readFile("./module.wasm")
);
Deno.serve(async (req) => {
const instance = await WebAssembly.instantiate(wasmModule);
const result = instance.exports.process(await req.text());
return new Response(String(result));
});
11.6 IoT 应用
Wasm 在 IoT 中的优势
传统 IoT 开发:
每种硬件 → 交叉编译 → 不同固件
维护 N 个版本 × M 种设备
Wasm + IoT:
源代码 → 编译为 Wasm → 任何设备
维护 1 个版本
+ 安全沙箱(防止恶意代码访问硬件)
+ OTA 更新(只需传输 .wasm 文件)
TinyGo + Wasm
// 使用 TinyGo 编译为 WASI
package main
import (
"fmt"
"math"
)
// 传感器数据处理
type SensorData struct {
Temperature float64
Humidity float64
Pressure float64
}
func (s SensorData) HeatIndex() float64 {
// 计算体感温度
t := s.Temperature
h := s.Humidity
return -8.7847 + 1.6114*t + 2.3385*h - 0.1461*t*h +
-0.0123*t*t - 0.0164*h*h + 0.0022*t*t*h +
0.0007*t*h*h - 0.0000036*t*t*h*h
}
func main() {
data := SensorData{Temperature: 25.0, Humidity: 60.0, Pressure: 1013.25}
fmt.Printf("Heat Index: %.2f\n", data.HeatIndex())
}
# 使用 TinyGo 编译
tinygo build -target wasi -o sensor.wasm main.go
# 在 IoT 设备上运行
wasm3 sensor.wasm
11.7 边缘函数实战:A/B 测试
use fastly::http::{Method, StatusCode};
use fastly::{Error, Request, Response};
static VARIANT_A: &str = r#"<h1>Welcome to Variant A</h1>"#;
static VARIANT_B: &str = r#"<h1>Welcome to Variant B</h1>"#;
#[fastly::main]
fn main(req: Request) -> Result<Response, Error> {
let cookie = req.get_header("Cookie").map(|v| v.to_str().unwrap_or(""));
let variant = match cookie {
Some(c) if c.contains("variant=a") => "A",
Some(c) if c.contains("variant=b") => "B",
_ => {
// 随机分配(使用简单的确定性哈希)
let ip = req.get_client_ip_addr().map(|ip| ip.to_string()).unwrap_or_default();
if ip.as_bytes().last().unwrap_or(&0) % 2 == 0 { "A" } else { "B" }
}
};
let body = if variant == "A" { VARIANT_A } else { VARIANT_B };
Ok(Response::from_status(StatusCode::OK)
.with_body_text_html(body)
.with_header("Set-Cookie", format!("variant={}; Path=/; Max-Age=86400", variant))
.with_header("X-Variant", variant))
}
11.8 边缘计算 vs 云函数
| 维度 | 边缘计算 (Wasm) | 云函数 (Lambda) |
|---|---|---|
| 冷启动 | < 1ms | 50ms - 数秒 |
| 延迟 | 10-50ms(取决于位置) | 50-500ms |
| 定价 | 按请求计费 | 按请求+时长计费 |
| 全球分布 | 300+ 节点 | 需要配置多区域 |
| 运行时限制 | CPU 时间限制 | CPU+内存+时间限制 |
| 文件系统 | 有限/无 | 临时存储 /tmp |
| 最大执行时间 | 通常 30s | 15 分钟 |
| 适用场景 | API 网关、路由、边缘逻辑 | 复杂计算、批处理 |
11.9 注意事项
⚠️ CPU 时间限制:边缘计算平台通常限制单次请求的 CPU 时间(如 Cloudflare Workers 免费版限制 10ms CPU 时间)。
⚠️ 内存限制:边缘节点内存有限(通常 128MB),大型 Wasm 模块可能无法加载。
⚠️ 无持久化文件系统:大多数边缘平台不提供持久化文件系统,需要使用 KV 存储或外部数据库。
⚠️ 冷启动优化:虽然 Wasm 冷启动快,但模块越大,编译时间越长。保持模块精简是关键。
11.10 扩展阅读
下一章:12 - 插件系统 — 使用 Wasm 构建安全的插件和扩展机制。