如何运行在边缘函数?

解读

“边缘函数”在国内通常指阿里云边缘函数计算(EdgeRoutine,ER)腾讯云边缘函数(Edge Functions)字节跳动边缘云函数Cloudflare WorkersServerless 运行时。它们的特点是:

  1. 冷启动极短(<5 ms),内存配额小(128 MB 以内),CPU 时间片受限(50 ms 级别)。
  2. 沙箱基于 V8 Isolate 或 WebAssembly,原生不支持 libc 与系统调用
  3. 入口必须是单文件、无状态、异步响应的“请求→响应”模型,禁止线程、文件、进程、动态链接库。

因此,面试官真正想考察的是:

  • 你是否理解“边缘”与“服务端”运行时的差异;
  • 能否把 Rust 代码编译成体积 <100 KB 的 WASM 模块,并暴露异步 HTTP Handler
  • 是否熟悉国内云厂商的构建工具链、产物上传、环境变量与日志采集流程。

知识点

  1. wasm32-wasi 与 wasm32-unknown-unknown 目标差异:边缘函数只认后者,因为 WASI 包含文件系统调用,会被沙箱拒绝。
  2. wasm-opt、wasm-snip、wee_alloc:三步裁剪,可把体积从 600 KB 压到 80 KB 以内。
  3. wasm-bindgen + js-sys + web-sys:生成 JavaScript 胶水,使 Rust 函数能被 V8 调用;边缘函数运行时已内置这些胶水,无需打包到产物
  4. 异步运行时选择:tokio 默认拉入 400 KB 标准库,边缘场景改用wasm-timer + futures-util + edge-runtime 提供的 fetch API即可。
  5. 国内厂商的“wasm 上传”入口
    • 阿里云 ER:控制台上传 .wasm + metadata.json(声明导出函数名与内存页上限)。
    • 腾讯云 Edge Functions:CLI 执行 tef deploy,自动把 pkg 目录打成单文件。
    • 字节边缘云:要求把 Cargo.toml 放在 Git 子目录,CI 自动编译并返回下载链接。
  6. 日志与监控:边缘函数 stdout 被收集到SLS 日志服务CLS,需用 console_log 宏输出 JSON,方便后续告警。

答案

阿里云 EdgeRoutine 为例,完整落地步骤如下:

  1. 安装工具链

    rustup target add wasm32-unknown-unknown
    cargo install wasm-bindgen-cli wasm-opt
    
  2. 创建最小工程

    cargo new --lib edge-hello
    cd edge-hello
    
  3. 编辑 Cargo.toml

    [package]
    name = "edge_hello"
    version = "0.1.0"
    edition = "2021"
    
    [lib]
    crate-type = ["cdylib"]
    
    [dependencies]
    wasm-bindgen = "0.2"
    wee_alloc = "0.4"
    serde = { version = "1.0", features = ["derive"] }
    serde_json = "1.0"
    
  4. 编写 src/lib.rs

    #![no_std]
    extern crate alloc;
    use alloc::string::String;
    use wasm_bindgen::prelude::*;
    
    #[global_allocator]
    static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
    
    #[wasm_bindgen]
    pub async fn handler(req: JsValue) -> Result<JsValue, JsValue> {
        let url = js_sys::Reflect::get(&req, &JsValue::from_str("url"))?
            .as_string().unwrap();
        let body = serde_json::json!({
            "msg": "hello from rust at edge",
            "url": url
        });
        Ok(JsValue::from_str(&body.to_string()))
    }
    
  5. 编译并裁剪

    cargo build --release --target wasm32-unknown-unknown
    wasm-bindgen --target no-modules --out-dir pkg \
      target/wasm32-unknown-unknown/release/edge_hello.wasm
    wasm-opt -Os -o pkg/edge_hello_bg_opt.wasm pkg/edge_hello_bg.wasm
    ls -lh pkg/edge_hello_bg_opt.wasm   # 应 <100 KB
    
  6. 准备 metadata.json

    {
      "entry": "handler",
      "memory": 256
    }
    
  7. 登录阿里云控制台 → EdgeRoutine → 创建函数 → 上传 edge_hello_bg_opt.wasmmetadata.json → 绑定域名 → 保存。

  8. 测试

    curl https://your-domain.com/test
    # 返回:{"msg":"hello from rust at edge","url":"https://your-domain.com/test"}
    

至此,Rust 代码已在边缘节点无服务器运行,冷启动 <3 ms,内存占用 <10 MB,满足国内大厂线上要求。

拓展思考

  1. 体积与性能权衡:若业务需要正则或加密,可启用 regex-literingwasm32-unknown-unknown feature,但体积会增至 150 KB;此时可用 brotli 预压缩 + 边缘缓存 把下载时间抵消。
  2. 灰度与回滚:国内云厂商普遍支持“版本别名 + 流量百分比”,可在 CLI 里 tef publish --traffic 5% 实现金丝雀发布;Rust 编译确定性高,可配合 Git SHA 做可重复构建
  3. 与 Node.js 混合部署:边缘函数允许一个域名下同时跑 JavaScript 与 WASM,若团队对 Rust 不熟悉,可先用 JS 做路由,热点路径下沉到 Rust WASM,逐步替换。
  4. 安全合规:边缘节点共享物理机,国内等保 2.0 要求密钥不可落盘;Rust 侧可用 zeroize 在内存清零敏感数据,并关闭 wee_alloc 的内存重用,防止跨租户嗅探。
  5. 未来趋势WASM Component ModelWASI Preview2 将在 2025 年落地,届时同一份 Rust 组件可无缝跑在边缘、浏览器与服务端,提前学习 wit-bindgenwasmtime 可占据技术红利。