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ý do | Hậu quả nếu không |
|---|---|
| User experience | 200ms latency lose khách hàng |
| Cost reduction | Edge giảm origin traffic 80% |
| DDoS mitigation | Edge absorb attack trước khi đến origin |
| Data sovereignty | Process locally, send only what needed |
| Wasm = polyglot | 1 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
- WebAssembly Spec — https://webassembly.org/
- WASI Preview 2 (Component Model) — https://github.com/WebAssembly/WASI
- Cloudflare Workers docs — https://developers.cloudflare.com/workers/
- Bytecode Alliance — https://bytecodealliance.org/
- wasmCloud (CNCF) — https://wasmcloud.com/
- Fermyon Spin — https://www.fermyon.com/spin
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
| Feature | Container | V8 Isolate | Wasm Module |
|---|---|---|---|
| Cold start | 100-1000ms | 5-50ms | <1ms |
| Memory overhead | 100MB+ | 10MB | <1MB |
| Languages | Any | JS only | Many (Rust, Go, C++) |
| Sandbox | OS-level | V8 | Wasm runtime |
| Density per host | 100s | 1000s | 10,000s |
| Maturity | Mature | Mature | Emerging (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
| Platform | Origin | Tech | Languages | Best for |
|---|---|---|---|---|
| Cloudflare Workers | Cloudflare | V8 + Wasm | JS/TS, Rust (Wasm), Python (Wasm) | Most use cases, cheapest |
| Vercel Edge | Vercel | V8 + Wasm | JS/TS | Next.js apps |
| Fastly Compute | Fastly | Wasm (Lucet, then Wasmtime) | Rust, JS, Go (TinyGo) | Wasm-first, performance |
| AWS Lambda@Edge | AWS | Container | Node.js, Python | AWS shop, simple tasks |
| AWS CloudFront Functions | AWS | JS subset | JS only | Lightweight CF rules |
| Deno Deploy | Deno | V8 isolate | JS/TS, Wasm | Deno enthusiasts |
| Akamai EdgeWorkers | Akamai | V8 | JS subset | Akamai 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
2.6 Cloudflare AI / D1 Vector Search
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/[email protected];
import wasi:filesystem/[email protected];
import wasi:http/[email protected];
export wasi:http/[email protected];
}→ 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 deploy2.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
| Platform | CPU/request | Memory |
|---|---|---|
| CF Workers | 50ms (free) - 30s (paid) | 128MB |
| Vercel Edge | 30s | 128MB |
| Fastly Compute | 100ms | 128MB |
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
| Runtime | Cold start | Warm start |
|---|---|---|
| Container (Lambda) | 200-1000ms | 1-50ms |
| V8 Isolate (Workers) | 5ms | 0.5ms |
| Wasm (Wasmtime) | 1-5ms | 0.1ms |
| Wasm (Wasmer) | 1-3ms | 0.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 deploy5.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 = true5.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 deploy5.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 up6.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.
9. Internal Links
| Topic | Liên hệ |
|---|---|
| Tuan-03-Networking-DNS-CDN | Foundation; edge extends CDN with compute |
| Tuan-04-API-Design-REST-gRPC | Edge serves APIs |
| Tuan-09-Rate-Limiter | Rate limit at edge with Durable Objects |
| Tuan-14-AuthN-AuthZ-Security | JWT verification at edge |
| Tuan-Bonus-MCP-Architecture | Cloudflare hosts Remote MCP servers |
| Tuan-Bonus-Multi-Region-Active-Active-DSQL | Edge + global DB |
Tham khảo
Specs:
- WebAssembly Spec — https://webassembly.org/
- WASI Preview 2 — https://github.com/WebAssembly/WASI
- Wasm Component Model — https://component-model.bytecodealliance.org/
Platforms:
- Cloudflare Workers — https://workers.cloudflare.com/
- Vercel Edge — https://vercel.com/docs/concepts/functions/edge-functions
- Fastly Compute — https://www.fastly.com/products/edge-compute
- Deno Deploy — https://deno.com/deploy
- Fermyon Spin — https://www.fermyon.com/spin
Tools:
- wasmCloud (CNCF) — https://wasmcloud.com/
- WasmEdge (CNCF) — https://wasmedge.org/
- Wasmtime — https://wasmtime.dev/
- wasm-pack (Rust) — https://rustwasm.github.io/wasm-pack/
Books:
- WebAssembly: The Definitive Guide (Brian Sletten, O’Reilly 2022)
- Programming WebAssembly with Rust (Kevin Hoffman, Pragmatic 2019)
Engineering blogs:
- Cloudflare Blog — https://blog.cloudflare.com/
- Bytecode Alliance — https://bytecodealliance.org/articles
- Fermyon Engineering — https://www.fermyon.com/blog
- Suborbital, Shopify Functions — Wasm in production
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.