强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

WebAssembly 入门教程 / 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 构建安全的插件和扩展机制。