Tuần Bonus: Edge Computing + WebAssembly Architecture

“Lambda cold start: 100-1000ms. Cloudflare Workers cold start: <1ms. Difference? Lambda = container, Workers = V8 isolate. Năm 2024-2026, Wasm Component Model làm cho ‘compute at edge’ = ‘run any language anywhere with sub-ms cold start’. Đây là evolution lớn nhất của serverless kể từ 2014.”

Tags: system-design edge-computing webassembly wasm cloudflare-workers bonus Student: Hieu (Backend Dev → Architect) Prerequisite: Tuan-03-Networking-DNS-CDN · Tuan-04-API-Design-REST-gRPC Liên quan: Tuan-Bonus-Multi-Region-Active-Active-DSQL · Tuan-Bonus-MCP-Architecture


1. Context & Why

Analogy đời thường — Mạng lưới điểm phục vụ

Hieu, tưởng tượng em mở chuỗi McDonald’s:

Mô hình cũ (cloud region):

  • 3-5 nhà bếp trung tâm: New York, London, Tokyo
  • Khách Việt Nam đặt qua app → request đi qua biển 200ms → bếp Tokyo → trả về
  • Mọi logic xử lý ở bếp trung tâm
  • Latency cao cho khách xa

Mô hình mới (edge computing):

  • 300+ điểm phục vụ nhỏ: mỗi thành phố lớn
  • Khách Việt Nam → điểm Hà Nội (5ms) → xử lý local
  • Chỉ cần đi về trung tâm cho data thật sự cần (database)
  • Latency thấp đáng kể

Edge Computing = chạy code gần user, WebAssembly (Wasm) = công nghệ enable run-anywhere với cold start cực thấp.

Tại sao Backend Dev cần hiểu Edge + Wasm?

Lý doHậu quả nếu không
User experience200ms latency lose khách hàng
Cost reductionEdge giảm origin traffic 80%
DDoS mitigationEdge absorb attack trước khi đến origin
Data sovereigntyProcess locally, send only what needed
Wasm = polyglot1 binary chạy everywhere (Linux, Win, browser, edge)
Cold start<1ms Wasm vs 100-1000ms container

Tại sao Alex Xu không đi sâu?

Alex Xu Vol 1+2 nói về CDN (cache static assets) nhưng không cover edge compute hiện đại. Cloudflare Workers production 2018, Wasm Component Model 2024 — đây là evolution gần đây.

Tham chiếu chính


2. Deep Dive — Khái niệm cốt lõi

2.1 Edge Computing Spectrum

Latency to user:
  Origin (cloud region):  50-300 ms
  Regional CDN:           20-100 ms
  Edge PoP:               5-30 ms
  Mobile Edge / 5G:       1-10 ms
  Device:                 <1 ms

Capability:
  Origin:    Full power, all data
  CDN:       Cache + simple rules
  Edge:      Compute + KV store + queues
  Device:    AI inference, encryption

2.2 Why WebAssembly?

Origins: 2017 Wasm spec finalized for browsers. Performance comparable to native code (within 10-30%) trong sandboxed environment.

Server-side renaissance (2020+):

  • Same sandbox security as JS, but faster
  • Polyglot: Rust, Go, C++, Python, JS all compile to Wasm
  • Tiny binaries (~100KB-1MB)
  • Sub-ms cold start (no container init)

2.2.1 Wasm vs Container vs JS Isolate

FeatureContainerV8 IsolateWasm Module
Cold start100-1000ms5-50ms<1ms
Memory overhead100MB+10MB<1MB
LanguagesAnyJS onlyMany (Rust, Go, C++)
SandboxOS-levelV8Wasm runtime
Density per host100s1000s10,000s
MaturityMatureMatureEmerging (server-side)

2.2.2 Wasm Component Model (2024)

Wasm Component Model: Beyond raw modules — composable components with typed interfaces.

# WIT (Wasm Interface Types)
package my-app:component
 
interface http {
    record request {
        method: string,
        path: string,
        body: list<u8>,
    }
 
    record response {
        status: u16,
        body: list<u8>,
    }
 
    handle: func(req: request) -> response
}
 
world my-component {
    export http
}

Magic:

  • Components from different languages compose
  • Typed interfaces (no FFI hell)
  • Capability-based security (component declares what it needs)

2.3 Cloudflare Workers — Production Edge Platform

Cloudflare Workers: V8 Isolate-based edge compute, runs at 300+ data centers.

Architecture:

User Request → Anycast IP → Nearest CF PoP (5-30ms)
                          → Worker runs in V8 isolate
                          → Optional: KV, R2, D1, Queues
                          → Response back

Key properties:

  • Cold start: ~5ms (V8 isolate)
  • 50ms CPU per request (paid tier higher)
  • 128MB memory
  • Run JavaScript, TypeScript, Rust (via Wasm), Python (via Pyodide Wasm)

Example Worker:

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const url = new URL(request.url);
 
    // Geo-routing
    const country = request.cf?.country;
    if (country === "VN") {
      return Response.redirect(`https://vn.example.com${url.pathname}`);
    }
 
    // KV cache
    const cached = await env.KV.get(`cache:${url.pathname}`);
    if (cached) {
      return new Response(cached, {
        headers: { "Cache-Control": "public, max-age=300" }
      });
    }
 
    // Fetch from origin
    const response = await fetch(`https://origin.example.com${url.pathname}`);
    const body = await response.text();
 
    // Cache
    ctx.waitUntil(env.KV.put(`cache:${url.pathname}`, body, {
      expirationTtl: 300
    }));
 
    return new Response(body, response);
  }
};

2.4 Edge Compute Platforms Comparison

PlatformOriginTechLanguagesBest for
Cloudflare WorkersCloudflareV8 + WasmJS/TS, Rust (Wasm), Python (Wasm)Most use cases, cheapest
Vercel EdgeVercelV8 + WasmJS/TSNext.js apps
Fastly ComputeFastlyWasm (Lucet, then Wasmtime)Rust, JS, Go (TinyGo)Wasm-first, performance
AWS Lambda@EdgeAWSContainerNode.js, PythonAWS shop, simple tasks
AWS CloudFront FunctionsAWSJS subsetJS onlyLightweight CF rules
Deno DeployDenoV8 isolateJS/TS, WasmDeno enthusiasts
Akamai EdgeWorkersAkamaiV8JS subsetAkamai customers

2.5 Edge Storage Options

2.5.1 Cloudflare KV (eventually consistent)

// KV: high read, low write, ~60s convergence
await env.KV.put("user:123:session", JSON.stringify(session), {
  expirationTtl: 3600
});
 
const data = await env.KV.get("user:123:session", "json");

Use cases: Session, A/B test buckets, content metadata. NOT primary store.

2.5.2 Cloudflare R2 (S3-compatible)

// R2: zero-egress S3 alternative
await env.MY_BUCKET.put("images/photo.jpg", imageData, {
  httpMetadata: { contentType: "image/jpeg" }
});
 
const obj = await env.MY_BUCKET.get("images/photo.jpg");

Pricing: 0 egress (vs S3 0.09/GB egress).

2.5.3 Cloudflare D1 (Edge SQL)

D1: SQLite at edge, replicated globally. Beta 2023, GA 2024.

const result = await env.DB.prepare(
  "SELECT * FROM users WHERE id = ?"
).bind(userId).first();

Limits:

  • 10 GB max DB size
  • Read-only replicas globally
  • Writes routed to primary region

2.5.4 Cloudflare Durable Objects

Durable Objects: Strongly consistent, single-instance state at edge.

export class Counter {
  state: DurableObjectState;
 
  constructor(state: DurableObjectState) {
    this.state = state;
  }
 
  async fetch(request: Request) {
    let value = (await this.state.storage.get<number>("value")) || 0;
    value += 1;
    await this.state.storage.put("value", value);
    return new Response(value.toString());
  }
}
 
// Each ID = unique instance globally
const id = env.COUNTER.idFromName("user-123");
const stub = env.COUNTER.get(id);
const response = await stub.fetch(request);

Use cases:

  • Real-time multiplayer game state
  • Chat rooms
  • CRDT synchronization
  • Per-user rate limiting

Workers AI: Run open-source models at edge.

const ai = new Ai(env.AI);
const response = await ai.run("@cf/meta/llama-3-8b-instruct", {
  messages: [{ role: "user", content: "Hello" }]
});

Vectorize: Vector DB at edge.

const vectors = await env.VECTORIZE.query(queryEmbedding, {
  topK: 5,
  filter: { tenant_id: "abc" }
});

2.7 WASI — WebAssembly System Interface

Problem: Wasm can’t talk to OS (file, network, etc.) by default.

WASI: Standard system interface. Components declare capabilities they need.

2.7.1 WASI Preview 1 (legacy)

// Rust compiled to wasm32-wasi
use std::fs;
 
fn main() {
    let content = fs::read_to_string("/data/input.txt").unwrap();
    println!("Read: {}", content);
}

2.7.2 WASI Preview 2 (Component Model, 2024)

Capability-based: Components only get what they request.

world my-app {
    import wasi:cli/environment@0.2.0;
    import wasi:filesystem/types@0.2.0;
    import wasi:http/outgoing-handler@0.2.0;
    export wasi:http/incoming-handler@0.2.0;
}

→ Component can read env vars, files, make HTTP calls. Nothing else.

2.8 Wasm Server-Side Use Cases

2.8.1 Plugin systems

Why: Run untrusted user code safely.

Examples:

  • Envoy filters (Wasm)
  • Istio proxy plugins
  • Kong plugins (Wasm)
  • Shopify Functions (Wasm)
  • Figma plugins
  • Database extensions (Postgres, ClickHouse)

2.8.2 Edge computing

Already discussed: Cloudflare, Fastly, etc.

2.8.3 Function-as-a-Service runtimes

Fermyon Spin: Open-source Wasm FaaS.

# Create new app
spin new my-app -t http-rust
 
# Deploy
spin build && spin up
 
# Or to cloud
spin deploy

2.8.4 Database UDFs

-- ClickHouse with Wasm UDF
CREATE FUNCTION my_func ENGINE = Wasm
  AS '/path/to/module.wasm';
 
SELECT my_func(column1) FROM my_table;

2.9 Production Patterns

2.9.1 Cache aside with edge

1. Edge worker receives request
2. Check edge cache (KV)
3. Cache miss → fetch from origin
4. Store in edge cache (TTL)
5. Return to user

Benefit: 80%+ requests served from edge, origin load reduced 5x

2.9.2 Auth at edge

export default {
  async fetch(request, env) {
    // Verify JWT at edge before reaching origin
    const token = request.headers.get("Authorization")?.replace("Bearer ", "");
 
    try {
      const payload = await jwtVerify(token, env.JWT_SECRET);
      // Pass through to origin with verified user
      return fetch(request, {
        headers: {
          ...request.headers,
          "X-User-ID": payload.sub
        }
      });
    } catch {
      return new Response("Unauthorized", { status: 401 });
    }
  }
};

Benefit: Invalid tokens rejected at edge. Origin only sees authenticated requests.

2.9.3 Rate limiting at edge

export default {
  async fetch(request, env) {
    const ip = request.headers.get("CF-Connecting-IP");
 
    // Use Durable Object for global rate limit state
    const id = env.RATE_LIMITER.idFromName(ip);
    const limiter = env.RATE_LIMITER.get(id);
    const allowed = await limiter.fetch(new Request("/check"));
 
    if (!allowed) {
      return new Response("Too many requests", { status: 429 });
    }
 
    return fetch(request);
  }
};

2.9.4 A/B testing at edge

export default {
  async fetch(request, env) {
    const userId = getUserId(request);
    const bucket = hash(userId) % 100;
 
    if (bucket < 10) {
      // 10% see new variant
      return fetch("https://new-variant.example.com");
    }
    return fetch("https://stable.example.com");
  }
};

2.9.5 Geo-routing & compliance

const country = request.cf?.country;
 
if (["DE", "FR", "IT"].includes(country)) {
  // EU users → EU origin (GDPR)
  return fetch(`https://eu.example.com${url.pathname}`);
}
if (country === "CN") {
  // China users → China origin
  return fetch(`https://cn.example.com${url.pathname}`);
}
return fetch(`https://us.example.com${url.pathname}`);

2.10 Edge Limitations

2.10.1 CPU & memory limits

PlatformCPU/requestMemory
CF Workers50ms (free) - 30s (paid)128MB
Vercel Edge30s128MB
Fastly Compute100ms128MB

Implication: No long-running tasks at edge. Use traditional cloud for those.

2.10.2 No long-lived connections

WebSocket → Durable Objects help (stateful), but mostly stateless.

2.10.3 Limited libraries

Edge runtimes lack many Node.js APIs. Need polyfills or Wasm versions.

2.10.4 Cold start vs warm

V8 isolates: nearly always warm at busy data centers. Wasm Components: similar. Lambda@Edge: cold start 100-300ms (much worse).


3. Estimation

3.1 Latency budget

API request without edge:

  • DNS: 20ms (cached: 0ms)
  • TLS handshake: 50-100ms
  • Network to origin: 50-200ms
  • Server processing: 50ms
  • Network back: 50-200ms
  • Total: 200-600ms

API request with edge:

  • DNS: cached
  • TLS: 5-20ms (kept-alive)
  • Network to edge: 5-30ms
  • Edge processing: 5-50ms
  • (If cache miss) Network to origin: 50-200ms
  • Network back: 5-30ms
  • Total: 20-300ms (50-90% faster)

3.2 Origin offload

Pattern: 80% of API responses cacheable at edge.

Without edge: 100M requests/day → all hit origin → $5K/day origin compute
With edge: 80M cached at edge, 20M to origin → $1K/day origin
Savings: $4K/day = $120K/month

Edge cost: Cloudflare Workers 0.50/M requests = $50K/month for 100M.

Net: Edge expensive at high volume but saves more on origin + better UX.

3.3 Wasm cold start

RuntimeCold startWarm start
Container (Lambda)200-1000ms1-50ms
V8 Isolate (Workers)5ms0.5ms
Wasm (Wasmtime)1-5ms0.1ms
Wasm (Wasmer)1-3ms0.1ms

Implication: Wasm enable serverless without cold start tax.

3.4 Pricing comparison

1M requests/day, 50ms each:

  • AWS Lambda: 30 compute = $50
  • Lambda@Edge: 60 compute = $90
  • CF Workers: 0.50/M × 30 = $20
  • Fastly Compute: X
  • Vercel Edge: X

CF Workers usually cheapest for stateless workloads.


4. Security First

4.1 Wasm sandbox security

Strong isolation:

  • No file system access by default
  • No network access by default
  • Capability-based: component declares what it needs
  • Memory isolated per instance
  • Verifiable bytecode (no buffer overflow)

Risks:

  • Side-channel attacks (Spectre/Meltdown) — mitigated by V8 hardening
  • Resource exhaustion (CPU/memory) — mitigated by limits
  • Privileged escalation — sandbox prevents

4.2 Edge-specific threats

DDoS: Edge absorbs attacks. Cloudflare anycast distributes load.

Cache poisoning: Cache key includes auth state.

const cacheKey = `${url.pathname}|${userTier}`;

Side-channel via timing: Don’t compare secrets at edge with ==. Use constant-time.

4.3 Auth at edge

JWT verification: Public key signature verification at edge (no DB lookup).

import { jwtVerify } from "jose";
 
const publicKey = await importJWK(env.JWT_PUBLIC_KEY);
const { payload } = await jwtVerify(token, publicKey);

Risks:

  • Public key rotation: serve via JWKS endpoint
  • Token revocation: difficult without DB lookup → short-lived tokens

4.4 Data residency

Edge gives flexibility:

// Process data without sending to US
if (country === "DE") {
  // Use EU R2 bucket
  return env.EU_BUCKET.put(key, data);
} else {
  return env.US_BUCKET.put(key, data);
}

But: edge code runs everywhere, so logic might process EU data globally. Need to validate.

4.5 Supply chain

Wasm modules from untrusted sources = risk.

Mitigations:

  • Signed Wasm modules (Sigstore for Wasm)
  • Capability inspection before deploy
  • Version pinning in registry

5. DevOps

5.1 Cloudflare Workers project

# Init
npm create cloudflare@latest my-worker
 
# Local dev
cd my-worker
npm run dev
 
# Deploy
npx wrangler deploy

5.2 wrangler.toml

name = "my-worker"
main = "src/index.ts"
compatibility_date = "2025-11-01"
 
[vars]
LOG_LEVEL = "info"
 
[[kv_namespaces]]
binding = "KV"
id = "abc123"
 
[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-app-data"
 
[[d1_databases]]
binding = "DB"
database_id = "..."
 
[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
 
[[migrations]]
tag = "v1"
new_classes = ["Counter"]
 
[ai]
binding = "AI"
 
[observability]
enabled = true

5.3 Spin (Wasm FaaS)

# Install
brew install fermyon/tap/spin
 
# Create
spin new my-app -t http-rust
 
# spin.toml structure:
# trigger = { type = "http" }
# component = { source = "target/wasm32-wasi/release/my_app.wasm" }
 
# Build & run
spin build
spin up
 
# Deploy to Fermyon Cloud
spin deploy

5.4 Monitoring

Cloudflare:

export default {
  async fetch(request, env, ctx) {
    const start = Date.now();
    try {
      const response = await handler(request, env);
 
      // Workers Analytics Engine
      env.ANALYTICS.writeDataPoint({
        blobs: [request.url, response.status.toString()],
        doubles: [Date.now() - start],
        indexes: [request.cf?.country || "unknown"]
      });
 
      return response;
    } catch (error) {
      console.error(error);
      env.ANALYTICS.writeDataPoint({
        blobs: ["error", error.message],
        doubles: [Date.now() - start]
      });
      return new Response("Error", { status: 500 });
    }
  }
};

Query analytics via SQL.

5.5 Testing

// Vitest with miniflare (CF Workers test runtime)
import { describe, it, expect } from "vitest";
import worker from "../src/index";
 
describe("Worker", () => {
  it("returns hello", async () => {
    const request = new Request("https://example.com");
    const response = await worker.fetch(request, env, ctx);
    expect(await response.text()).toBe("Hello");
  });
});

6. Code Implementation

6.1 Edge API Gateway (Cloudflare Workers)

// API gateway with auth, rate limit, routing at edge
import { Hono } from "hono";
import { jwt } from "hono/jwt";
 
interface Env {
  KV: KVNamespace;
  RATE_LIMITER: DurableObjectNamespace;
  ORIGIN_URL: string;
  JWT_SECRET: string;
}
 
const app = new Hono<{ Bindings: Env }>();
 
// JWT auth middleware
app.use("/api/*", async (c, next) => {
  const token = c.req.header("Authorization")?.replace("Bearer ", "");
  if (!token) return c.json({ error: "Unauthorized" }, 401);
 
  try {
    const payload = await verifyJWT(token, c.env.JWT_SECRET);
    c.set("user", payload);
    await next();
  } catch {
    return c.json({ error: "Invalid token" }, 401);
  }
});
 
// Rate limiting via Durable Object
app.use("*", async (c, next) => {
  const ip = c.req.header("CF-Connecting-IP") || "unknown";
  const id = c.env.RATE_LIMITER.idFromName(ip);
  const limiter = c.env.RATE_LIMITER.get(id);
 
  const allowed = await limiter.fetch("https://check");
  if (!await allowed.json()) {
    return c.json({ error: "Rate limited" }, 429);
  }
 
  await next();
});
 
// Cache aside
app.get("/api/data/:id", async (c) => {
  const id = c.req.param("id");
  const cacheKey = `data:${id}`;
 
  const cached = await c.env.KV.get(cacheKey);
  if (cached) {
    return c.json(JSON.parse(cached), 200, {
      "X-Cache": "HIT"
    });
  }
 
  const response = await fetch(`${c.env.ORIGIN_URL}/data/${id}`);
  const data = await response.json();
 
  // Async cache write (don't block response)
  c.executionCtx.waitUntil(
    c.env.KV.put(cacheKey, JSON.stringify(data), {
      expirationTtl: 300
    })
  );
 
  return c.json(data, 200, { "X-Cache": "MISS" });
});
 
// Geo-routing
app.get("/", async (c) => {
  const country = c.req.raw.cf?.country;
 
  if (country === "DE") {
    return Response.redirect("https://de.example.com");
  }
  if (["JP", "KR", "VN"].includes(country)) {
    return Response.redirect("https://asia.example.com");
  }
  return Response.redirect("https://example.com");
});
 
export default app;
 
 
// Durable Object for rate limiting
export class RateLimiter {
  state: DurableObjectState;
  requests: number[] = [];
 
  constructor(state: DurableObjectState) {
    this.state = state;
  }
 
  async fetch(request: Request): Promise<Response> {
    const now = Date.now();
    // Keep last 60 seconds
    this.requests = this.requests.filter(t => t > now - 60_000);
 
    if (this.requests.length >= 100) {
      return Response.json(false);
    }
 
    this.requests.push(now);
    return Response.json(true);
  }
}

6.2 Wasm component in Rust

// Cargo.toml
// [lib]
// crate-type = ["cdylib"]
//
// [dependencies]
// wasi-http = "0.4"
 
use wasi::http::types::{IncomingRequest, ResponseOutparam};
use wasi::http::proxy::export;
 
struct MyHandler;
 
impl Guest for MyHandler {
    fn handle(request: IncomingRequest, response_out: ResponseOutparam) {
        let path = request.path_with_query().unwrap_or_default();
 
        let body = format!(r#"{{"path":"{}", "runtime":"wasm"}}"#, path);
 
        // Build response
        let response = OutgoingResponse::new(
            Fields::new(),
        );
        response.set_status_code(200);
 
        // Write body
        let body_handle = response.body().unwrap();
        let stream = body_handle.write().unwrap();
        stream.blocking_write_and_flush(body.as_bytes()).unwrap();
 
        ResponseOutparam::set(response_out, Ok(response));
    }
}
 
export!(MyHandler);
# Build
cargo component build --release
 
# Deploy to wasmCloud
wash app deploy my-app.wadm.yaml
 
# Or to Spin
spin up

6.3 Edge AI inference

// Sentiment analysis at edge using Workers AI
export default {
  async fetch(request, env) {
    const { text } = await request.json();
 
    const ai = new Ai(env.AI);
    const result = await ai.run(
      "@cf/huggingface/distilbert-sst-2-int8",
      { text }
    );
 
    return Response.json({
      text,
      sentiment: result[0].label,
      confidence: result[0].score
    });
  }
};
// Embedding generation + vector search
const embedding = await ai.run(
  "@cf/baai/bge-base-en-v1.5",
  { text: query }
);
 
const matches = await env.VECTORIZE.query(embedding.data[0], {
  topK: 5
});
 
return Response.json(matches);

7. System Design Diagrams

7.1 Edge Architecture

flowchart TB
    Users[Users globally] --> Anycast[Cloudflare Anycast IP]

    Anycast --> POPVN[PoP Hanoi<br/>5ms]
    Anycast --> POPUS[PoP New York<br/>5ms]
    Anycast --> POPEU[PoP London<br/>5ms]
    Anycast --> POPJP[PoP Tokyo<br/>5ms]

    POPVN --> Worker1[Worker]
    POPUS --> Worker2[Worker]
    POPEU --> Worker3[Worker]
    POPJP --> Worker4[Worker]

    Worker1 --> EdgeCache[Edge KV<br/>cached at PoP]
    Worker2 --> EdgeCache

    Worker1 --> Origin[Origin Cloud<br/>only on cache miss]
    Worker3 --> Origin
    Origin --> DB[(Database)]

    style EdgeCache fill:#c8e6c9
    style Origin fill:#fff9c4

7.2 Wasm Component Composition

flowchart LR
    subgraph Components["Wasm Components (different langs)"]
        C1[Auth Component<br/>Rust]
        C2[Rate Limit Component<br/>Go]
        C3[Cache Component<br/>JS/AssemblyScript]
        C4[Logic Component<br/>Python]
    end

    Request[HTTP Request] --> C1 --> C2 --> C3 --> C4 --> Response[HTTP Response]

    Note["Components compose via<br/>typed WIT interfaces<br/>regardless of source language"]

    style Note fill:#bbdefb

7.3 V8 Isolate vs Container

flowchart TB
    subgraph Container["Container (Lambda)"]
        ContReq[Request]
        ContReq --> ContColdStart{Cold start?}
        ContColdStart -->|Yes 100-1000ms| ContInit[Init container<br/>Load runtime<br/>Load app code]
        ContColdStart -->|No| ContRun[Run handler]
        ContInit --> ContRun
        ContRun --> ContResp[Response]
    end

    subgraph Isolate["V8 Isolate (Workers)"]
        IsoReq[Request]
        IsoReq --> IsoCold{Cold start?}
        IsoCold -->|Yes ~5ms| IsoInit[Compile script]
        IsoCold -->|No| IsoRun[Run handler]
        IsoInit --> IsoRun
        IsoRun --> IsoResp[Response]
    end

    Note1[100-1000x slower cold start]
    Note2[Multiple isolates per process,<br/>no per-request OS overhead]

    style Container fill:#ffcdd2
    style Isolate fill:#c8e6c9

7.4 Edge + Origin Pattern

sequenceDiagram
    participant U as User
    participant E as Edge Worker
    participant K as Edge KV
    participant O as Origin
    participant D as Origin DB

    U->>E: GET /api/products/123
    E->>E: Verify JWT
    E->>K: Get cache key
    alt Cache hit
        K-->>E: cached data
        E-->>U: 200 (cache hit, 10ms)
    else Cache miss
        E->>O: Fetch from origin
        O->>D: Query DB
        D-->>O: result
        O-->>E: response
        E->>K: Store cache (async)
        E-->>U: 200 (cache miss, 100ms)
    end

8. Aha Moments & Pitfalls

Aha Moments

#1: Edge ≠ CDN. CDN caches static. Edge runs code. Different paradigm.

#2: V8 Isolates revolutionary. 5ms cold start enables serverless without cold start tax. Workers innovation 2018.

#3: Wasm = polyglot edge. Rust, Go, Python all compile to Wasm. Same binary runs in browser, server, edge.

#4: Capability-based security. Component declares “I need HTTP + filesystem”. Anything else = denied. Stronger than “trusted code”.

#5: R2 zero egress = game changer. S3 charges 0. For high-bandwidth use cases, 50-90% cost savings.

#6: Durable Objects = strongly consistent at edge. Single-instance globally per ID. Use for chat rooms, counters, real-time game state.

#7: Edge AI changing inference. Workers AI runs Llama 3.1 at edge. <100ms inference vs 500ms+ to cloud.

#8: Wasm Component Model fixes interop. Beyond raw modules → typed interfaces. Industry standard 2024+.

Pitfalls

Pitfall 1: Long-running tasks at edge

30s task at Cloudflare Workers (free tier) → killed at 10ms. Fix: Use queues + workers. Edge for orchestration, cloud for compute.

Pitfall 2: Heavy state at edge

Large in-memory cache → memory exhausted. Fix: Use KV/D1/Durable Objects for state, edge code stateless.

Pitfall 3: Region-specific data sent globally

User uploads EU data, edge replicates to US KV. Fix: Region-aware routing, separate buckets per region.

Pitfall 4: Cold start in Lambda@Edge

Use Lambda@Edge expecting fast → 100-300ms cold starts kill UX. Fix: Use Workers/Vercel Edge for low cold start. Lambda@Edge for AWS-tight integration only.

Pitfall 5: No fallback

Edge fails → no fallback to origin → users see errors. Fix: Edge code wraps origin call with retry + timeout.

Pitfall 6: KV strong consistency expectations

Write KV, read immediately → may get old value. Fix: KV is eventually consistent (~60s convergence). Use Durable Objects for strong consistency.

Pitfall 7: Tight CPU loops at edge

Heavy CPU work in Worker → hits 50ms limit. Fix: Wasm for compute-heavy (more CPU efficient). Or queue to backend.

Pitfall 8: Wasm module too large

10MB Wasm binary → slow cold start, large bandwidth. Fix: Tree shaking, AOT compile, optimize binary size.

Pitfall 9: No observability

Edge code hard to debug without proper logging. Fix: Structured logs, distributed tracing, Workers Analytics.

Pitfall 10: Lock-in

Build on Cloudflare-specific APIs → hard to migrate. Fix: Use OpenFeature, OpenTelemetry, standard APIs where possible.


TopicLiên hệ
Tuan-03-Networking-DNS-CDNFoundation; edge extends CDN with compute
Tuan-04-API-Design-REST-gRPCEdge serves APIs
Tuan-09-Rate-LimiterRate limit at edge with Durable Objects
Tuan-14-AuthN-AuthZ-SecurityJWT verification at edge
Tuan-Bonus-MCP-ArchitectureCloudflare hosts Remote MCP servers
Tuan-Bonus-Multi-Region-Active-Active-DSQLEdge + global DB

Tham khảo

Specs:

Platforms:

Tools:

Books:

  • WebAssembly: The Definitive Guide (Brian Sletten, O’Reilly 2022)
  • Programming WebAssembly with Rust (Kevin Hoffman, Pragmatic 2019)

Engineering blogs:


Hoàn thành toàn bộ Phase F + G (7 file). Vault giờ cover comprehensively các topic kiến trúc 2024-2026.