Skip to content

Split View: WebAssembly 완전 가이드 2025: 브라우저를 넘어서 — WASI, Component Model, 서버사이드 Wasm

✨ Learn with Quiz
|

WebAssembly 완전 가이드 2025: 브라우저를 넘어서 — WASI, Component Model, 서버사이드 Wasm

목차

1. WebAssembly란 무엇인가

WebAssembly(Wasm)는 스택 기반 가상 머신을 위한 바이너리 명령어 포맷이다. 원래 웹 브라우저에서 네이티브에 가까운 성능을 제공하기 위해 설계되었지만, 이제는 브라우저를 넘어 서버, 엣지, IoT까지 확장되고 있다.

1.1 Wasm의 핵심 특성

특성설명의미
바이너리 포맷컴팩트한 바이너리 인코딩빠른 전송, 빠른 디코딩
스택 머신스택 기반 명령어 실행단순하고 효율적인 실행 모델
선형 메모리연속된 바이트 배열안전한 메모리 접근, 샌드박스
타입 안전강타입 시스템컴파일 시 검증, 런타임 안전
이식성아키텍처 독립적x86, ARM, RISC-V 어디서나 실행
샌드박스격리된 실행 환경호스트 시스템 보호

1.2 Wasm의 역사

2015: WebAssembly 프로젝트 발표 (W3C)
2017: 4대 브라우저에서 Wasm 1.0 지원
2019: WASI 초기 제안 (비브라우저 Wasm)
2020: Wasm 1.0W3C 공식 권고안
2021: Component Model 제안, Fermyon 창립
2022: Docker+Wasm 기술 프리뷰, WASI Preview 1
2023: WASI 0.2 안정화, Component Model 성숙
2024: GC proposal 구현, 주요 런타임 최적화
2025: WASI 0.2 Production-ready, Wasm 서버 본격 채택

1.3 Wasm 바이너리 구조

Wasm 모듈 구조:
+------------------+
| Magic Number     |  0x00 0x61 0x73 0x6D ("\0asm")
| Version          |  0x01 0x00 0x00 0x00 (v1)
+------------------+
| Type Section     |  함수 시그니처 정의
| Import Section   |  외부 함수/메모리 임포트
| Function Section |  함수 인덱스
| Table Section    |  간접 호출 테이블
| Memory Section   |  선형 메모리 정의
| Global Section   |  전역 변수
| Export Section   |  외부 공개 함수/메모리
| Start Section    |  자동 실행 함수
| Element Section  |  테이블 초기화
| Code Section     |  함수 본문 (바이트코드)
| Data Section     |  메모리 초기 데이터
+------------------+

1.4 WAT (WebAssembly Text Format)

Wasm의 텍스트 표현 형식인 WAT를 이해하면 내부 동작을 파악할 수 있다.

;; 두 수를 더하는 간단한 Wasm 모듈
(module
  ;; 함수 타입 정의
  (type $add_type (func (param i32 i32) (result i32)))

  ;; 함수 구현
  (func $add (type $add_type) (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.add
  )

  ;; 선형 메모리 (1 페이지 = 64KB)
  (memory (export "memory") 1)

  ;; 함수 내보내기
  (export "add" (func $add))
)

2. 브라우저 Wasm

2.1 다양한 언어에서 Wasm으로 컴파일

Rust - Wasm 1등 시민

// lib.rs - Rust에서 Wasm으로
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
    if n <= 1 {
        return n as u64;
    }
    let mut a: u64 = 0;
    let mut b: u64 = 1;
    for _ in 2..=n {
        let temp = a + b;
        a = b;
        b = temp;
    }
    b
}

#[wasm_bindgen]
pub struct ImageProcessor {
    width: u32,
    height: u32,
    pixels: Vec<u8>,
}

#[wasm_bindgen]
impl ImageProcessor {
    #[wasm_bindgen(constructor)]
    pub fn new(width: u32, height: u32) -> ImageProcessor {
        ImageProcessor {
            width,
            height,
            pixels: vec![0; (width * height * 4) as usize],
        }
    }

    pub fn grayscale(&mut self) {
        for chunk in self.pixels.chunks_exact_mut(4) {
            let gray = (0.299 * chunk[0] as f64
                + 0.587 * chunk[1] as f64
                + 0.114 * chunk[2] as f64) as u8;
            chunk[0] = gray;
            chunk[1] = gray;
            chunk[2] = gray;
        }
    }

    pub fn pixels_ptr(&self) -> *const u8 {
        self.pixels.as_ptr()
    }
}
# Rust -> Wasm 빌드
wasm-pack build --target web

C/C++ - Emscripten

// image_filter.c - C에서 Wasm으로
#include <emscripten.h>
#include <stdint.h>

EMSCRIPTEN_KEEPALIVE
void apply_blur(uint8_t* pixels, int width, int height) {
    uint8_t* temp = (uint8_t*)malloc(width * height * 4);

    for (int y = 1; y < height - 1; y++) {
        for (int x = 1; x < width - 1; x++) {
            for (int c = 0; c < 3; c++) {
                int sum = 0;
                for (int dy = -1; dy <= 1; dy++) {
                    for (int dx = -1; dx <= 1; dx++) {
                        sum += pixels[((y+dy)*width + (x+dx))*4 + c];
                    }
                }
                temp[(y*width + x)*4 + c] = sum / 9;
            }
            temp[(y*width + x)*4 + 3] = pixels[(y*width + x)*4 + 3];
        }
    }

    memcpy(pixels, temp, width * height * 4);
    free(temp);
}
# C -> Wasm 빌드
emcc image_filter.c -O3 -s WASM=1 \
  -s EXPORTED_FUNCTIONS='["_apply_blur"]' \
  -s EXPORTED_RUNTIME_METHODS='["cwrap"]' \
  -o image_filter.js

2.2 JavaScript와의 상호 운용

// Wasm 모듈 로드 및 사용
async function initWasm() {
  // 방법 1: fetch + instantiate
  const response = await fetch('module.wasm');
  const bytes = await response.arrayBuffer();
  const { instance } = await WebAssembly.instantiate(bytes, {
    env: {
      // 호스트 함수를 Wasm에 제공
      log_value: (value) => console.log('Wasm says:', value),
      get_time: () => Date.now(),
    }
  });

  // Wasm 함수 호출
  const result = instance.exports.add(10, 20);
  console.log('Result:', result); // 30

  // 선형 메모리 접근
  const memory = new Uint8Array(instance.exports.memory.buffer);
  // 메모리에서 데이터 읽기/쓰기

  return instance;
}

// 방법 2: wasm-bindgen (Rust)
import init, { fibonacci, ImageProcessor } from './pkg/my_wasm.js';

async function main() {
  await init();

  console.log('fib(40):', fibonacci(40));

  const processor = new ImageProcessor(800, 600);
  processor.grayscale();
}

2.3 브라우저 Wasm 주요 사용 사례

사용 사례예시성능 향상
이미지/비디오 처리Photoshop Web, FFmpeg.wasm10-50x JS 대비
게임 엔진Unity WebGL, Unreal Engine네이티브의 70-90%
코덱/압축AV1 디코딩, Brotli 압축5-20x JS 대비
암호화SHA-256, AES 연산3-10x JS 대비
CAD/3D 모델링AutoCAD Web, SketchUp네이티브 수준
과학 계산시뮬레이션, 데이터 분석10-100x JS 대비
PDF 처리pdf.js 가속, 렌더링3-5x 향상

3. WASI 0.2: 시스템 인터페이스

WASI(WebAssembly System Interface)는 Wasm이 브라우저 밖에서 파일시스템, 네트워크 등 시스템 리소스에 안전하게 접근하기 위한 표준이다.

3.1 WASI 0.2 인터페이스

WASI 0.2 구조:
+----------------------------------+
| wasi:cli        (CLI 앱 지원)    |
| wasi:http       (HTTP 클라이언트/서버) |
| wasi:filesystem (파일시스템 접근)  |
| wasi:sockets    (네트워크 소켓)   |
| wasi:clocks     (시간 관련)      |
| wasi:random     (난수 생성)      |
| wasi:io         (스트림 I/O)     |
+----------------------------------+
| Component Model (기반 레이어)     |
+----------------------------------+
| Wasm Core (실행 엔진)           |
+----------------------------------+

3.2 WASI HTTP 서버 (Rust)

// Rust + WASI HTTP 서버
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct TodoItem {
    id: u32,
    title: String,
    completed: bool,
}

#[http_component]
fn handle_request(req: Request) -> anyhow::Result<impl IntoResponse> {
    let method = req.method().as_str();
    let path = req.path();

    match (method, path) {
        ("GET", "/api/todos") => {
            let todos = vec![
                TodoItem { id: 1, title: "Learn WASI".into(), completed: false },
                TodoItem { id: 2, title: "Build Wasm app".into(), completed: false },
            ];
            Ok(Response::builder()
                .status(200)
                .header("content-type", "application/json")
                .body(serde_json::to_string(&todos)?)
                .build())
        },
        ("POST", "/api/todos") => {
            let body: TodoItem = serde_json::from_slice(req.body())?;
            Ok(Response::builder()
                .status(201)
                .header("content-type", "application/json")
                .body(serde_json::to_string(&body)?)
                .build())
        },
        _ => Ok(Response::builder()
            .status(404)
            .body("Not Found")
            .build())
    }
}

3.3 Capability-Based 보안 모델

WASI는 Capability-Based Security를 핵심으로 한다. 프로그램은 명시적으로 부여받은 권한만 사용할 수 있다.

# WASI 실행 시 권한 부여 예시
# 특정 디렉터리만 읽기 허용
wasmtime run --dir /data::/data:readonly my-app.wasm

# 네트워크 접근 허용
wasmtime run --tcplisten 0.0.0.0:8080 my-server.wasm

# 환경 변수 전달
wasmtime run --env KEY=VALUE my-app.wasm
기존 보안 모델 (Ambient Authority):
  프로세스 -> [전체 파일시스템 접근 가능]
           -> [모든 네트워크 접근 가능]
           -> [환경 변수 모두 읽기 가능]

WASI 보안 모델 (Capability-Based):
  Wasm 모듈 -> [/data 디렉터리만 읽기 가능]
            -> [localhost:8080만 리슨 가능]
            -> [지정된 환경 변수만 접근 가능]

4. Component Model: 모듈 조합

Component Model은 Wasm 모듈을 조합하여 복잡한 애플리케이션을 구성하는 표준이다.

4.1 WIT (Wasm Interface Type)

// todo.wit - 인터페이스 정의
package example:todo@0.1.0;

interface types {
    record todo-item {
        id: u32,
        title: string,
        completed: bool,
    }

    variant todo-error {
        not-found(string),
        validation-error(string),
        storage-error(string),
    }
}

interface todo-store {
    use types.{todo-item, todo-error};

    list-todos: func() -> result<list<todo-item>, todo-error>;
    get-todo: func(id: u32) -> result<todo-item, todo-error>;
    create-todo: func(title: string) -> result<todo-item, todo-error>;
    update-todo: func(id: u32, title: string, completed: bool) -> result<todo-item, todo-error>;
    delete-todo: func(id: u32) -> result<_, todo-error>;
}

world todo-app {
    import wasi:http/outgoing-handler@0.2.0;
    import wasi:logging/logging;

    export todo-store;
}

4.2 Component 조합

# 여러 컴포넌트를 조합하여 하나의 앱 구성
# 1. 각 컴포넌트 빌드
cargo component build --release  # Rust 컴포넌트
componentize-py -d todo.wit -w todo-app app.py  # Python 컴포넌트

# 2. 컴포넌트 조합
wasm-tools compose \
  --definitions auth-component.wasm \
  --definitions db-component.wasm \
  app-component.wasm \
  -o composed-app.wasm

# 3. 조합된 컴포넌트 실행
wasmtime serve composed-app.wasm

4.3 Component Model의 장점

장점설명
언어 독립적 조합Rust 모듈 + Python 모듈 + Go 모듈을 하나로
타입 안전한 인터페이스WIT로 정의된 계약 보장
샌드박스 격리컴포넌트 간 메모리 격리
경량컨테이너 대비 수십 배 가벼움
빠른 시작마이크로초 단위 초기화
이식성어디서나 실행 가능

5. 서버사이드 Wasm 프레임워크

5.1 Fermyon Spin

Spin은 Wasm 기반 마이크로서비스를 빌드하기 위한 프레임워크다.

# spin.toml - Spin 앱 설정
spin_manifest_version = 2

[application]
name = "my-api"
version = "1.0.0"
description = "Wasm 기반 API 서버"

[[trigger.http]]
route = "/api/hello"
component = "hello"

[[trigger.http]]
route = "/api/users/..."
component = "users"

[component.hello]
source = "target/wasm32-wasi/release/hello.wasm"
allowed_outbound_hosts = []

[component.users]
source = "target/wasm32-wasi/release/users.wasm"
allowed_outbound_hosts = ["https://api.example.com"]
key_value_stores = ["default"]
sqlite_databases = ["default"]
// Spin HTTP 핸들러 (Rust)
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;
use spin_sdk::key_value::Store;

#[http_component]
fn handle_request(req: Request) -> anyhow::Result<impl IntoResponse> {
    // Key-Value 스토어 사용
    let store = Store::open_default()?;

    match req.method().as_str() {
        "GET" => {
            let key = req.path().trim_start_matches("/api/users/");
            match store.get(key)? {
                Some(value) => Ok(Response::builder()
                    .status(200)
                    .header("content-type", "application/json")
                    .body(value)
                    .build()),
                None => Ok(Response::builder()
                    .status(404)
                    .body("Not found")
                    .build()),
            }
        },
        "POST" => {
            let body = req.body().to_vec();
            let key = format!("user:{}", uuid::Uuid::new_v4());
            store.set(&key, &body)?;

            Ok(Response::builder()
                .status(201)
                .header("content-type", "application/json")
                .body(body)
                .build())
        },
        _ => Ok(Response::builder()
            .status(405)
            .body("Method not allowed")
            .build()),
    }
}
# Spin 앱 빌드 및 실행
spin build
spin up  # 로컬 실행 (포트 3000)

# Fermyon Cloud에 배포
spin deploy

5.2 wasmCloud

wasmCloud는 분산 Wasm 애플리케이션 플랫폼이다.

# wadm.yaml - wasmCloud 앱 매니페스트
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: my-api
  annotations:
    description: "wasmCloud HTTP API"
spec:
  components:
    - name: api-handler
      type: component
      properties:
        image: ghcr.io/myorg/api-handler:0.1.0
      traits:
        - type: spreadscaler
          properties:
            instances: 5
        - type: link
          properties:
            target: httpserver
            namespace: wasi
            package: http
            interfaces: [incoming-handler]

    - name: httpserver
      type: capability
      properties:
        image: ghcr.io/wasmcloud/http-server:0.22.0
      traits:
        - type: link
          properties:
            target: api-handler
            namespace: wasi
            package: http
            interfaces: [incoming-handler]
            source_config:
              - name: default-http
                properties:
                  address: 0.0.0.0:8080

5.3 서버사이드 Wasm 프레임워크 비교

특성Fermyon SpinwasmCloudLunatic
초점HTTP 마이크로서비스분산 애플리케이션액터 모델
배포 모델단일 노드 / 클라우드분산 격자 (lattice)클러스터
스토리지KV, SQLite, RedisCapability Provider내장
언어 지원Rust, Go, JS, PythonRust, Go, AssemblyScriptRust, AssemblyScript
콜드 스타트1ms 미만1ms 미만수 ms
성숙도GAGA초기
클라우드 서비스Fermyon CloudCosmonic없음

6. Docker + Wasm

Docker Desktop은 Wasm 컨테이너를 네이티브로 지원한다.

6.1 Docker Wasm 아키텍처

기존 Linux 컨테이너:
  Docker Engine -> containerd -> runc -> Linux Container
                                         (full OS, 수십~수백 MB)

Wasm 컨테이너:
  Docker Engine -> containerd -> runwasi -> Wasm Runtime (wasmtime/wasmedge)
                                            (Wasm 모듈,MB)

6.2 Wasm Docker 이미지 빌드

# Dockerfile.wasm - Wasm 컨테이너 이미지
FROM scratch
COPY target/wasm32-wasi/release/my-app.wasm /my-app.wasm
ENTRYPOINT ["/my-app.wasm"]
# Wasm 이미지 빌드 및 실행
docker buildx build --platform wasi/wasm -t my-wasm-app .
docker run --runtime=io.containerd.wasmtime.v1 \
  --platform wasi/wasm \
  -p 8080:8080 \
  my-wasm-app

6.3 Docker Compose with Wasm

# docker-compose.yml - Wasm + Linux 컨테이너 혼합
version: "3"

services:
  # Wasm 서비스 (초경량)
  api:
    image: my-wasm-api:latest
    runtime: io.containerd.wasmtime.v1
    platform: wasi/wasm
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=postgres

  # 전통적인 Linux 컨테이너
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data

  # Wasm 워커 서비스
  worker:
    image: my-wasm-worker:latest
    runtime: io.containerd.wasmtime.v1
    platform: wasi/wasm
    environment:
      - QUEUE_URL=redis://redis:6379

  redis:
    image: redis:7-alpine

volumes:
  pgdata:

6.4 Wasm vs Linux 컨테이너 비교

특성Linux 컨테이너Wasm 컨테이너
이미지 크기50MB-1GB1-10MB
시작 시간100ms-수초1ms 미만
메모리 사용50MB-수GB1-50MB
보안 모델네임스페이스/cgroup샌드박스/Capability
이식성Linux 커널 필요아키텍처 독립
프로세스 격리OS 수준언어 수준
네트워킹완전 지원WASI 소켓 (제한적)
파일시스템완전 지원WASI FS (제한적)

7. Edge Wasm

7.1 Cloudflare Workers

// Cloudflare Worker (Wasm 기반)
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    if (url.pathname === '/api/compute') {
      // Wasm 모듈로 무거운 계산 수행
      const wasmModule = await import('./compute.wasm');
      const result = wasmModule.heavy_computation(42);

      return new Response(JSON.stringify({ result }), {
        headers: { 'Content-Type': 'application/json' }
      });
    }

    // KV 스토어 사용
    if (url.pathname.startsWith('/api/cache/')) {
      const key = url.pathname.split('/').pop();

      if (request.method === 'GET') {
        const value = await env.MY_KV.get(key);
        return new Response(value || 'Not found', {
          status: value ? 200 : 404
        });
      }

      if (request.method === 'PUT') {
        const body = await request.text();
        await env.MY_KV.put(key, body, { expirationTtl: 3600 });
        return new Response('OK');
      }
    }

    return new Response('Not found', { status: 404 });
  }
};

7.2 Fastly Compute

// Fastly Compute (Rust + Wasm)
use fastly::{Error, Request, Response};
use fastly::http::StatusCode;

#[fastly::main]
fn main(req: Request) -> Result<Response, Error> {
    let path = req.get_path().to_string();

    match path.as_str() {
        "/api/hello" => {
            Ok(Response::from_status(StatusCode::OK)
                .with_body_text_plain("Hello from Fastly Compute!"))
        },
        path if path.starts_with("/api/proxy/") => {
            // 백엔드로 프록시
            let backend_path = path.trim_start_matches("/api/proxy");
            let mut backend_req = req;
            backend_req.set_path(backend_path);
            backend_req.send("origin_backend")
        },
        _ => {
            Ok(Response::from_status(StatusCode::NOT_FOUND)
                .with_body_text_plain("Not found"))
        }
    }
}

7.3 Edge Wasm 플랫폼 비교

플랫폼런타임언어콜드 스타트무료 티어
Cloudflare WorkersV8 + WasmJS, Rust, C++0ms (상시 로드)10만 요청/일
Fastly ComputeWasmtimeRust, Go, JS수 ms없음
Vercel Edge FunctionsV8 + WasmJS, TS0ms (상시 로드)100만 실행/월
Deno DeployV8 + WasmJS, TS, Wasm0ms10만 요청/일
Fermyon CloudSpinRust, Go, JS, Python1ms 미만무료 베타

8. 언어별 Wasm 지원

8.1 Rust - 1등 시민

Rust는 Wasm의 가장 강력한 언어 지원을 제공한다.

// Cargo.toml
[package]
name = "my-wasm-app"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wit-bindgen = "0.25"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# 빌드 타겟
rustup target add wasm32-wasi     # WASI 타겟
rustup target add wasm32-unknown-unknown  # 브라우저 타겟

# 빌드
cargo build --target wasm32-wasi --release

# Component로 변환
wasm-tools component new target/wasm32-wasi/release/my_app.wasm \
  -o my_app.component.wasm

8.2 Go - TinyGo

// main.go - TinyGo Wasm
package main

import (
    "encoding/json"
    "net/http"

    spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
)

type Response struct {
    Message string `json:"message"`
    Count   int    `json:"count"`
}

func init() {
    spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
        resp := Response{
            Message: "Hello from Go Wasm!",
            Count:   42,
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(resp)
    })
}

func main() {}
# TinyGo로 Wasm 빌드
tinygo build -target=wasi -o main.wasm main.go

8.3 Python - componentize-py

# app.py - Python Wasm (Spin)
from spin_sdk.http import IncomingHandler, Request, Response
import json

class IncomingHandler(IncomingHandler):
    def handle_request(self, request: Request) -> Response:
        if request.method == "GET" and request.uri == "/api/hello":
            body = json.dumps({
                "message": "Hello from Python Wasm!",
                "path": request.uri,
            })
            return Response(
                200,
                {"content-type": "application/json"},
                bytes(body, "utf-8")
            )

        return Response(404, {}, b"Not found")
# Python -> Wasm 컴포넌트
componentize-py -d spin-http.wit -w spin-http-trigger app -o app.wasm

8.4 JavaScript - jco

// app.js - JavaScript Wasm Component
import { handle } from 'wasi:http/incoming-handler@0.2.0';

export const incomingHandler = {
  handle(request, responseOut) {
    const headers = new Headers();
    headers.set('Content-Type', 'application/json');

    const body = JSON.stringify({
      message: 'Hello from JS Wasm!',
      method: request.method(),
      path: request.pathWithQuery(),
    });

    const response = new OutgoingResponse(headers);
    response.setStatusCode(200);

    const bodyStream = response.body();
    bodyStream.write(new TextEncoder().encode(body));
    bodyStream.close();

    responseOut.set(response);
  }
};
# JavaScript -> Wasm Component
jco componentize app.js -w wasi-http.wit -o app.wasm

8.5 언어 지원 비교

언어Wasm 성숙도WASI 지원Component Model바이너리 크기비고
Rust매우 높음완전완전1-5MB1등 시민
C/C++높음완전부분적0.5-3MBEmscripten
Go (TinyGo)중간완전완전2-10MB표준 Go 일부 미지원
Python중간완전완전10-30MBcomponentize-py
JavaScript중간완전완전5-15MBjco
C# (.NET)중간부분적초기10-50MBNativeAOT-LLVM
Swift초기부분적초기5-20MBSwiftWasm
Kotlin초기부분적초기10-30MBKotlin/Wasm

9. 성능 비교

9.1 콜드 스타트 비교

플랫폼콜드 스타트메모리 사용비고
Wasm (Spin)0.5-1ms2-10MB마이크로초 수준
Wasm (wasmtime)1-5ms5-20MB일반적
Lambda (Python)150-300ms50-128MBVPC 추가 시 더 느림
Lambda (Java)800-3000ms128-512MBSnapStart로 개선 가능
Docker Container500-5000ms50MB-1GB이미지 크기 의존
Cloud Run300-2000ms128MB-8GB인스턴스 타입 의존

9.2 처리량 비교

HTTP "Hello World" 벤치마크 (단일 인스턴스):

Spin (Rust/Wasm):     ~150,000 req/s
Native Rust (Actix):  ~200,000 req/s
Go (net/http):        ~120,000 req/s
Node.js (Express):    ~30,000 req/s
Python (FastAPI):     ~10,000 req/s

Wasm은 네이티브의 70-90% 성능을 달성

9.3 메모리 효율성

단일 HTTP 서비스 메모리 사용:

Wasm (Spin):          2-5 MB
Wasm (wasmtime):      5-15 MB
Node.js:              30-80 MB
Python:               30-60 MB
Java (JVM):           100-300 MB
.NET:                 50-150 MB
Go:                   10-30 MB

1GB 메모리에서 동시 서비스 수:
Wasm: ~200개 서비스
Node.js: ~15개 서비스
Java: ~5개 서비스

10. 보안 모델

10.1 Wasm 샌드박스

전통적인 프로세스:
+------------------------------------------+
| 프로세스                                  |
|  - 전체 파일시스템 접근                     |
|  - 모든 네트워크 접근                       |
|  - 시스템 콜 무제한                         |
|  - 다른 프로세스 메모리 접근 (exploit 시)    |
+------------------------------------------+

Wasm 샌드박스:
+------------------------------------------+
| Wasm 모듈                                |
|  +------------------------------------+  |
|  | 선형 메모리 (모듈 전용)               |  |
|  | - 경계 검사 (bounds checking)        |  |
|  | - 호스트 메모리 접근 불가              |  |
|  +------------------------------------+  |
|  | 허가된 시스템 인터페이스만 사용         |  |
|  | - wasi:filesystem (지정 경로만)       |  |
|  | - wasi:sockets (지정 주소만)          |  |
|  +------------------------------------+  |
+------------------------------------------+

10.2 Capability-Based Security 원칙

원칙설명예시
No Ambient Authority기본 권한 없음파일시스템, 네트워크 접근 불가
Principle of Least Privilege최소 권한만 부여특정 디렉터리만 접근 허용
Explicit Capability Passing명시적 권한 전달호스트가 핸들을 전달
Revocable권한 회수 가능런타임에 권한 제거

10.3 보안 비교

보안 측면컨테이너Wasm
격리 수준OS 수준 (cgroup/namespace)언어 수준 (바이트코드 검증)
메모리 안전커널에 의존경계 검사 내장
시스템 콜seccomp으로 필터링WASI로 제한
탈출 가능성커널 취약점 시 가능매우 어려움
권한 모델유저/그룹 기반Capability 기반
코드 검증없음로드 시 검증

11. 실전 사용 사례

11.1 플러그인 시스템

// 호스트 애플리케이션 - 플러그인 로더
use wasmtime::*;
use wasmtime_wasi::WasiCtxBuilder;

fn load_plugin(plugin_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let engine = Engine::default();
    let mut linker = Linker::new(&engine);
    wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;

    // 플러그인에 최소 권한만 부여
    let wasi = WasiCtxBuilder::new()
        .inherit_stdout()  // stdout만 허용
        // 파일시스템 접근 없음
        // 네트워크 접근 없음
        .build();

    let mut store = Store::new(&engine, wasi);
    let module = Module::from_file(&engine, plugin_path)?;
    let instance = linker.instantiate(&mut store, &module)?;

    // 플러그인 함수 호출
    let process = instance
        .get_typed_func::<(i32,), i32>(&mut store, "process")?;
    let result = process.call(&mut store, (42,))?;

    println!("Plugin result: {}", result);
    Ok(())
}

11.2 Edge Computing

Edge Wasm 아키텍처:

사용자 요청 -> [CDN Edge (300+ PoP)]
                 |
                 v
              [Wasm Worker]
                 |
                 +-> 캐시 히트: 즉시 응답 (0ms)
                 |
                 +-> 캐시 미스: 원본 서버에 요청
                 |              |
                 |              v
                 |         [Origin Server]
                 |              |
                 v              v
              [응답 + 캐시 저장]

장점:
- 사용자에게 가장 가까운 위치에서 실행
- 콜드 스타트 거의 없음
- 글로벌 분산 자동 배포

11.3 Serverless Functions

Lambda vs Wasm Serverless:

AWS Lambda:
  요청 -> API Gateway -> Lambda Runtime -> 함수 실행
  콜드 스타트: 100ms-8s
  메모리: 128MB-10GB
  과금: 1ms 단위

Wasm Serverless (Spin/Fermyon):
  요청 -> Spin Runtime -> Wasm 모듈 실행
  콜드 스타트: 0.5ms 이하
  메모리: 2-50MB
  과금: 요청 단위

11.4 블록체인 스마트 컨트랙트

여러 블록체인이 Wasm을 스마트 컨트랙트 실행 엔진으로 채택했다.

블록체인Wasm 런타임언어 지원
PolkadotSubstrateRust (ink!)
NearWasmerRust, AssemblyScript
Cosmos (CosmWasm)WasmerRust
Dfinity (ICP)커스텀Rust, Motoko

12. Wasm vs Container 비교

12.1 종합 비교

특성WasmContainer
시작 시간마이크로초-밀리초밀리초-초
이미지 크기1-50MB50MB-수GB
메모리 사용1-50MB50MB-수GB
CPU 오버헤드0-30%0-5%
보안강한 샌드박스OS 수준 격리
네트워킹WASI (제한적)완전 지원
파일시스템WASI (제한적)완전 지원
GPU 지원실험적완전 지원
에코시스템성장 중매우 성숙
디버깅발전 중성숙
상태 관리Stateless 권장Stateful 가능

12.2 언제 Wasm을 선택하나

Wasm 선택 기준:

  • 밀리초 이하 콜드 스타트 필요
  • 극한의 경량 서비스
  • 플러그인/확장 시스템
  • Edge 컴퓨팅
  • 다중 언어 모듈 조합
  • 강한 샌드박스 격리 필요
  • 제한된 리소스 환경 (IoT)

Container 선택 기준:

  • 복잡한 네트워킹
  • GPU 사용
  • 레거시 애플리케이션
  • 풍부한 에코시스템 필요
  • 상태 보존 필요
  • 대용량 메모리/스토리지

13. 미래 전망

13.1 진행 중인 Wasm 제안

제안상태설명
GC (Garbage Collection)Phase 4Java, Kotlin, Dart 등 GC 언어 지원
ThreadsPhase 3공유 메모리 멀티스레딩
SIMDPhase 4 (완료)128비트 SIMD 연산
Exception HandlingPhase 4try/catch 네이티브 지원
Stack SwitchingPhase 2코루틴, async/await 지원
Memory64Phase 364비트 메모리 주소
Branch HintingPhase 3분기 예측 힌트
Tail CallPhase 4 (완료)꼬리 호출 최적화

13.2 Wasm 미래 로드맵

2025-2026 전망:
- WASI 0.2 완전 안정화 및 주요 클라우드 채택
- Component Model 생태계 성숙
- Docker Wasm 프로덕션 레디
- GC proposal 주요 런타임 구현
- Threads proposal 안정화

2027+ 전망:
- Wasm이 컨테이너와 동등한 위상
- Edge-first 아키텍처의 기본 런타임
- IoT/임베디드 표준 실행 환경
- 다중 언어 컴포넌트 생태계 확립

14. 퀴즈

Q1. WASI의 핵심 보안 모델은 무엇인가?

정답: Capability-Based Security (권한 기반 보안)

WASI는 "No Ambient Authority" 원칙을 따른다. Wasm 모듈은 기본적으로 아무 권한도 없으며, 호스트가 명시적으로 부여한 capability(파일 핸들, 네트워크 소켓 등)만 사용할 수 있다. 이는 전통적인 Unix의 ambient authority 모델과 대비된다.

Q2. Wasm Component Model의 장점은?

정답:

  • 언어 독립적 조합: Rust, Python, Go 등 서로 다른 언어로 작성된 모듈을 하나로 조합 가능
  • WIT 인터페이스: 타입 안전한 계약으로 모듈 간 통신
  • 샌드박스 격리: 각 컴포넌트는 자신만의 메모리 공간을 가짐
  • 경량: 컨테이너 대비 수십 배 가벼움
Q3. Wasm의 콜드 스타트가 Lambda보다 빠른 이유는?

정답:

  • Wasm 바이너리는 1-10MB로 매우 작아 로딩이 빠름
  • 런타임 초기화가 마이크로초 수준 (JVM이나 Python 인터프리터 같은 무거운 초기화 없음)
  • AOT 컴파일된 바이너리 직접 실행
  • 선형 메모리 모델로 간단한 메모리 설정
  • 프로세스/컨테이너 생성 오버헤드 없음
Q4. Docker + Wasm은 어떻게 동작하는가?

정답:

Docker Desktop은 containerd의 runwasi shim을 사용하여 Wasm 컨테이너를 실행한다. 기존의 runc 대신 wasmtime이나 wasmedge 같은 Wasm 런타임이 컨테이너를 실행한다. FROM scratch 기반 이미지에 .wasm 파일만 포함하여 초경량 이미지를 만들 수 있고, docker-compose에서 Linux 컨테이너와 Wasm 컨테이너를 혼합 운용할 수 있다.

Q5. Wasm이 아직 컨테이너를 대체할 수 없는 이유는?

정답:

  • WASI의 시스템 인터페이스가 아직 제한적 (GPU, 복잡한 네트워킹 등)
  • 에코시스템이 컨테이너에 비해 미성숙
  • 레거시 애플리케이션 마이그레이션이 어려움
  • 상태 관리가 기본적으로 stateless
  • 디버깅 도구가 아직 발전 중
  • 일부 언어의 Wasm 지원이 초기 단계

단, Wasm은 컨테이너를 "대체"하기보다 "보완"하는 기술로, Edge와 경량 서비스 영역에서 컨테이너와 공존할 전망이다.


15. 참고 자료

  1. WebAssembly 공식 사이트 - https://webassembly.org/
  2. WASI 공식 문서 - https://wasi.dev/
  3. Component Model 명세 - https://component-model.bytecodealliance.org/
  4. Fermyon Spin 문서 - https://developer.fermyon.com/spin/
  5. wasmCloud 문서 - https://wasmcloud.com/docs/
  6. Bytecode Alliance - https://bytecodealliance.org/
  7. wasmtime 런타임 - https://wasmtime.dev/
  8. Docker Wasm 가이드 - https://docs.docker.com/desktop/wasm/
  9. Cloudflare Workers - https://developers.cloudflare.com/workers/
  10. Fastly Compute - https://developer.fastly.com/learning/compute/
  11. wasm-tools - https://github.com/bytecodealliance/wasm-tools
  12. WIT 명세 - https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md
  13. componentize-py - https://github.com/bytecodealliance/componentize-py

WebAssembly Complete Guide 2025: Beyond the Browser — WASI, Component Model, Server-Side Wasm

Table of Contents

1. What is WebAssembly

WebAssembly (Wasm) is a binary instruction format for a stack-based virtual machine. Originally designed to provide near-native performance in web browsers, it has now expanded beyond the browser to servers, edge computing, and IoT.

1.1 Core Characteristics of Wasm

CharacteristicDescriptionSignificance
Binary FormatCompact binary encodingFast transmission, fast decoding
Stack MachineStack-based instruction executionSimple and efficient execution model
Linear MemoryContiguous byte arraySafe memory access, sandboxing
Type SafetyStrong type systemCompile-time verification, runtime safety
PortabilityArchitecture independentRuns on x86, ARM, RISC-V anywhere
SandboxIsolated execution environmentHost system protection

1.2 History of Wasm

2015: WebAssembly project announced (W3C)
2017: Wasm 1.0 supported in all 4 major browsers
2019: WASI initial proposal (non-browser Wasm)
2020: Wasm 1.0 becomes W3C official recommendation
2021: Component Model proposal, Fermyon founded
2022: Docker+Wasm tech preview, WASI Preview 1
2023: WASI 0.2 stabilized, Component Model matures
2024: GC proposal implemented, major runtime optimizations
2025: WASI 0.2 production-ready, server-side Wasm adoption accelerates

1.3 Wasm Binary Structure

Wasm Module Structure:
+------------------+
| Magic Number     |  0x00 0x61 0x73 0x6D ("\0asm")
| Version          |  0x01 0x00 0x00 0x00 (v1)
+------------------+
| Type Section     |  Function signature definitions
| Import Section   |  External function/memory imports
| Function Section |  Function indices
| Table Section    |  Indirect call tables
| Memory Section   |  Linear memory definition
| Global Section   |  Global variables
| Export Section   |  Publicly exposed functions/memory
| Start Section    |  Auto-execution function
| Element Section  |  Table initialization
| Code Section     |  Function bodies (bytecode)
| Data Section     |  Initial memory data
+------------------+

1.4 WAT (WebAssembly Text Format)

Understanding WAT, the text representation of Wasm, helps grasp its internal workings.

;; A simple Wasm module that adds two numbers
(module
  ;; Function type definition
  (type $add_type (func (param i32 i32) (result i32)))

  ;; Function implementation
  (func $add (type $add_type) (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.add
  )

  ;; Linear memory (1 page = 64KB)
  (memory (export "memory") 1)

  ;; Export function
  (export "add" (func $add))
)

2. Browser Wasm

2.1 Compiling to Wasm from Various Languages

Rust - First-Class Wasm Citizen

// lib.rs - Rust to Wasm
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
    if n <= 1 {
        return n as u64;
    }
    let mut a: u64 = 0;
    let mut b: u64 = 1;
    for _ in 2..=n {
        let temp = a + b;
        a = b;
        b = temp;
    }
    b
}

#[wasm_bindgen]
pub struct ImageProcessor {
    width: u32,
    height: u32,
    pixels: Vec<u8>,
}

#[wasm_bindgen]
impl ImageProcessor {
    #[wasm_bindgen(constructor)]
    pub fn new(width: u32, height: u32) -> ImageProcessor {
        ImageProcessor {
            width,
            height,
            pixels: vec![0; (width * height * 4) as usize],
        }
    }

    pub fn grayscale(&mut self) {
        for chunk in self.pixels.chunks_exact_mut(4) {
            let gray = (0.299 * chunk[0] as f64
                + 0.587 * chunk[1] as f64
                + 0.114 * chunk[2] as f64) as u8;
            chunk[0] = gray;
            chunk[1] = gray;
            chunk[2] = gray;
        }
    }

    pub fn pixels_ptr(&self) -> *const u8 {
        self.pixels.as_ptr()
    }
}
# Rust -> Wasm build
wasm-pack build --target web

C/C++ - Emscripten

// image_filter.c - C to Wasm
#include <emscripten.h>
#include <stdint.h>

EMSCRIPTEN_KEEPALIVE
void apply_blur(uint8_t* pixels, int width, int height) {
    uint8_t* temp = (uint8_t*)malloc(width * height * 4);

    for (int y = 1; y < height - 1; y++) {
        for (int x = 1; x < width - 1; x++) {
            for (int c = 0; c < 3; c++) {
                int sum = 0;
                for (int dy = -1; dy <= 1; dy++) {
                    for (int dx = -1; dx <= 1; dx++) {
                        sum += pixels[((y+dy)*width + (x+dx))*4 + c];
                    }
                }
                temp[(y*width + x)*4 + c] = sum / 9;
            }
            temp[(y*width + x)*4 + 3] = pixels[(y*width + x)*4 + 3];
        }
    }

    memcpy(pixels, temp, width * height * 4);
    free(temp);
}
# C -> Wasm build
emcc image_filter.c -O3 -s WASM=1 \
  -s EXPORTED_FUNCTIONS='["_apply_blur"]' \
  -s EXPORTED_RUNTIME_METHODS='["cwrap"]' \
  -o image_filter.js

2.2 JavaScript Interop

// Loading and using Wasm modules
async function initWasm() {
  // Method 1: fetch + instantiate
  const response = await fetch('module.wasm');
  const bytes = await response.arrayBuffer();
  const { instance } = await WebAssembly.instantiate(bytes, {
    env: {
      // Provide host functions to Wasm
      log_value: (value) => console.log('Wasm says:', value),
      get_time: () => Date.now(),
    }
  });

  // Call Wasm function
  const result = instance.exports.add(10, 20);
  console.log('Result:', result); // 30

  // Access linear memory
  const memory = new Uint8Array(instance.exports.memory.buffer);
  // Read/write data in memory

  return instance;
}

// Method 2: wasm-bindgen (Rust)
import init, { fibonacci, ImageProcessor } from './pkg/my_wasm.js';

async function main() {
  await init();

  console.log('fib(40):', fibonacci(40));

  const processor = new ImageProcessor(800, 600);
  processor.grayscale();
}

2.3 Key Browser Wasm Use Cases

Use CaseExamplesPerformance Gain
Image/Video ProcessingPhotoshop Web, FFmpeg.wasm10-50x vs JS
Game EnginesUnity WebGL, Unreal Engine70-90% of native
Codecs/CompressionAV1 decoding, Brotli compression5-20x vs JS
CryptographySHA-256, AES operations3-10x vs JS
CAD/3D ModelingAutoCAD Web, SketchUpNear-native
Scientific ComputingSimulations, data analysis10-100x vs JS
PDF Processingpdf.js acceleration, rendering3-5x improvement

3. WASI 0.2: System Interface

WASI (WebAssembly System Interface) is a standard for Wasm to safely access system resources like filesystems and networks outside the browser.

3.1 WASI 0.2 Interfaces

WASI 0.2 Structure:
+----------------------------------+
| wasi:cli        (CLI app support)|
| wasi:http       (HTTP client/server) |
| wasi:filesystem (Filesystem access)  |
| wasi:sockets    (Network sockets)    |
| wasi:clocks     (Time-related)       |
| wasi:random     (Random generation)  |
| wasi:io         (Stream I/O)         |
+----------------------------------+
| Component Model (Foundation layer)   |
+----------------------------------+
| Wasm Core (Execution engine)         |
+----------------------------------+

3.2 WASI HTTP Server (Rust)

// Rust + WASI HTTP Server
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct TodoItem {
    id: u32,
    title: String,
    completed: bool,
}

#[http_component]
fn handle_request(req: Request) -> anyhow::Result<impl IntoResponse> {
    let method = req.method().as_str();
    let path = req.path();

    match (method, path) {
        ("GET", "/api/todos") => {
            let todos = vec![
                TodoItem { id: 1, title: "Learn WASI".into(), completed: false },
                TodoItem { id: 2, title: "Build Wasm app".into(), completed: false },
            ];
            Ok(Response::builder()
                .status(200)
                .header("content-type", "application/json")
                .body(serde_json::to_string(&todos)?)
                .build())
        },
        ("POST", "/api/todos") => {
            let body: TodoItem = serde_json::from_slice(req.body())?;
            Ok(Response::builder()
                .status(201)
                .header("content-type", "application/json")
                .body(serde_json::to_string(&body)?)
                .build())
        },
        _ => Ok(Response::builder()
            .status(404)
            .body("Not Found")
            .build())
    }
}

3.3 Capability-Based Security Model

WASI's core security model is capability-based. Programs can only use permissions explicitly granted to them.

# WASI runtime capability examples
# Allow read-only access to specific directory
wasmtime run --dir /data::/data:readonly my-app.wasm

# Allow network access
wasmtime run --tcplisten 0.0.0.0:8080 my-server.wasm

# Pass environment variables
wasmtime run --env KEY=VALUE my-app.wasm
Traditional Security Model (Ambient Authority):
  Process -> [Full filesystem access]
          -> [All network access]
          -> [All env variables readable]

WASI Security Model (Capability-Based):
  Wasm Module -> [Only /data directory, read-only]
              -> [Only listen on localhost:8080]
              -> [Only specified env variables accessible]

4. Component Model: Module Composition

The Component Model is a standard for composing Wasm modules into complex applications.

4.1 WIT (Wasm Interface Type)

// todo.wit - Interface definition
package example:todo@0.1.0;

interface types {
    record todo-item {
        id: u32,
        title: string,
        completed: bool,
    }

    variant todo-error {
        not-found(string),
        validation-error(string),
        storage-error(string),
    }
}

interface todo-store {
    use types.{todo-item, todo-error};

    list-todos: func() -> result<list<todo-item>, todo-error>;
    get-todo: func(id: u32) -> result<todo-item, todo-error>;
    create-todo: func(title: string) -> result<todo-item, todo-error>;
    update-todo: func(id: u32, title: string, completed: bool) -> result<todo-item, todo-error>;
    delete-todo: func(id: u32) -> result<_, todo-error>;
}

world todo-app {
    import wasi:http/outgoing-handler@0.2.0;
    import wasi:logging/logging;

    export todo-store;
}

4.2 Component Composition

# Compose multiple components into a single app
# 1. Build each component
cargo component build --release  # Rust component
componentize-py -d todo.wit -w todo-app app.py  # Python component

# 2. Compose components
wasm-tools compose \
  --definitions auth-component.wasm \
  --definitions db-component.wasm \
  app-component.wasm \
  -o composed-app.wasm

# 3. Run composed component
wasmtime serve composed-app.wasm

4.3 Benefits of the Component Model

BenefitDescription
Language-Independent CompositionCombine Rust + Python + Go modules into one
Type-Safe InterfacesContracts guaranteed by WIT definitions
Sandbox IsolationMemory isolation between components
LightweightTens of times lighter than containers
Fast StartupMicrosecond-level initialization
PortabilityRuns anywhere

5. Server-Side Wasm Frameworks

5.1 Fermyon Spin

Spin is a framework for building Wasm-based microservices.

# spin.toml - Spin app configuration
spin_manifest_version = 2

[application]
name = "my-api"
version = "1.0.0"
description = "Wasm-based API server"

[[trigger.http]]
route = "/api/hello"
component = "hello"

[[trigger.http]]
route = "/api/users/..."
component = "users"

[component.hello]
source = "target/wasm32-wasi/release/hello.wasm"
allowed_outbound_hosts = []

[component.users]
source = "target/wasm32-wasi/release/users.wasm"
allowed_outbound_hosts = ["https://api.example.com"]
key_value_stores = ["default"]
sqlite_databases = ["default"]
// Spin HTTP handler (Rust)
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;
use spin_sdk::key_value::Store;

#[http_component]
fn handle_request(req: Request) -> anyhow::Result<impl IntoResponse> {
    // Use Key-Value store
    let store = Store::open_default()?;

    match req.method().as_str() {
        "GET" => {
            let key = req.path().trim_start_matches("/api/users/");
            match store.get(key)? {
                Some(value) => Ok(Response::builder()
                    .status(200)
                    .header("content-type", "application/json")
                    .body(value)
                    .build()),
                None => Ok(Response::builder()
                    .status(404)
                    .body("Not found")
                    .build()),
            }
        },
        "POST" => {
            let body = req.body().to_vec();
            let key = format!("user:{}", uuid::Uuid::new_v4());
            store.set(&key, &body)?;

            Ok(Response::builder()
                .status(201)
                .header("content-type", "application/json")
                .body(body)
                .build())
        },
        _ => Ok(Response::builder()
            .status(405)
            .body("Method not allowed")
            .build()),
    }
}
# Build and run Spin app
spin build
spin up  # Local run (port 3000)

# Deploy to Fermyon Cloud
spin deploy

5.2 wasmCloud

wasmCloud is a distributed Wasm application platform.

# wadm.yaml - wasmCloud app manifest
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: my-api
  annotations:
    description: "wasmCloud HTTP API"
spec:
  components:
    - name: api-handler
      type: component
      properties:
        image: ghcr.io/myorg/api-handler:0.1.0
      traits:
        - type: spreadscaler
          properties:
            instances: 5
        - type: link
          properties:
            target: httpserver
            namespace: wasi
            package: http
            interfaces: [incoming-handler]

    - name: httpserver
      type: capability
      properties:
        image: ghcr.io/wasmcloud/http-server:0.22.0
      traits:
        - type: link
          properties:
            target: api-handler
            namespace: wasi
            package: http
            interfaces: [incoming-handler]
            source_config:
              - name: default-http
                properties:
                  address: 0.0.0.0:8080

5.3 Server-Side Wasm Framework Comparison

FeatureFermyon SpinwasmCloudLunatic
FocusHTTP microservicesDistributed applicationsActor model
Deploy ModelSingle node / CloudDistributed latticeCluster
StorageKV, SQLite, RedisCapability ProvidersBuilt-in
Language SupportRust, Go, JS, PythonRust, Go, AssemblyScriptRust, AssemblyScript
Cold StartSub-1msSub-1msFew ms
MaturityGAGAEarly
Cloud ServiceFermyon CloudCosmonicNone

6. Docker + Wasm

Docker Desktop natively supports Wasm containers.

6.1 Docker Wasm Architecture

Traditional Linux Container:
  Docker Engine -> containerd -> runc -> Linux Container
                                         (full OS, tens-hundreds MB)

Wasm Container:
  Docker Engine -> containerd -> runwasi -> Wasm Runtime (wasmtime/wasmedge)
                                            (Wasm module, few MB)

6.2 Building Wasm Docker Images

# Dockerfile.wasm - Wasm container image
FROM scratch
COPY target/wasm32-wasi/release/my-app.wasm /my-app.wasm
ENTRYPOINT ["/my-app.wasm"]
# Build and run Wasm image
docker buildx build --platform wasi/wasm -t my-wasm-app .
docker run --runtime=io.containerd.wasmtime.v1 \
  --platform wasi/wasm \
  -p 8080:8080 \
  my-wasm-app

6.3 Docker Compose with Wasm

# docker-compose.yml - Mixed Wasm + Linux containers
version: "3"

services:
  # Wasm service (ultra-lightweight)
  api:
    image: my-wasm-api:latest
    runtime: io.containerd.wasmtime.v1
    platform: wasi/wasm
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=postgres

  # Traditional Linux container
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data

  # Wasm worker service
  worker:
    image: my-wasm-worker:latest
    runtime: io.containerd.wasmtime.v1
    platform: wasi/wasm
    environment:
      - QUEUE_URL=redis://redis:6379

  redis:
    image: redis:7-alpine

volumes:
  pgdata:

6.4 Wasm vs Linux Container Comparison

FeatureLinux ContainerWasm Container
Image Size50MB-1GB1-10MB
Startup Time100ms-secondsSub-1ms
Memory Usage50MB-GBs1-50MB
Security ModelNamespaces/cgroupsSandbox/Capability
PortabilityRequires Linux kernelArchitecture independent
Process IsolationOS levelLanguage level
NetworkingFull supportWASI sockets (limited)
FilesystemFull supportWASI FS (limited)

7. Edge Wasm

7.1 Cloudflare Workers

// Cloudflare Worker (Wasm-based)
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    if (url.pathname === '/api/compute') {
      // Perform heavy computation with Wasm module
      const wasmModule = await import('./compute.wasm');
      const result = wasmModule.heavy_computation(42);

      return new Response(JSON.stringify({ result }), {
        headers: { 'Content-Type': 'application/json' }
      });
    }

    // Use KV store
    if (url.pathname.startsWith('/api/cache/')) {
      const key = url.pathname.split('/').pop();

      if (request.method === 'GET') {
        const value = await env.MY_KV.get(key);
        return new Response(value || 'Not found', {
          status: value ? 200 : 404
        });
      }

      if (request.method === 'PUT') {
        const body = await request.text();
        await env.MY_KV.put(key, body, { expirationTtl: 3600 });
        return new Response('OK');
      }
    }

    return new Response('Not found', { status: 404 });
  }
};

7.2 Fastly Compute

// Fastly Compute (Rust + Wasm)
use fastly::{Error, Request, Response};
use fastly::http::StatusCode;

#[fastly::main]
fn main(req: Request) -> Result<Response, Error> {
    let path = req.get_path().to_string();

    match path.as_str() {
        "/api/hello" => {
            Ok(Response::from_status(StatusCode::OK)
                .with_body_text_plain("Hello from Fastly Compute!"))
        },
        path if path.starts_with("/api/proxy/") => {
            // Proxy to backend
            let backend_path = path.trim_start_matches("/api/proxy");
            let mut backend_req = req;
            backend_req.set_path(backend_path);
            backend_req.send("origin_backend")
        },
        _ => {
            Ok(Response::from_status(StatusCode::NOT_FOUND)
                .with_body_text_plain("Not found"))
        }
    }
}

7.3 Edge Wasm Platform Comparison

PlatformRuntimeLanguagesCold StartFree Tier
Cloudflare WorkersV8 + WasmJS, Rust, C++0ms (always loaded)100K req/day
Fastly ComputeWasmtimeRust, Go, JSFew msNone
Vercel Edge FunctionsV8 + WasmJS, TS0ms (always loaded)1M exec/month
Deno DeployV8 + WasmJS, TS, Wasm0ms100K req/day
Fermyon CloudSpinRust, Go, JS, PythonSub-1msFree beta

8. Language Support for Wasm

8.1 Rust - First-Class Citizen

Rust provides the strongest language support for Wasm.

// Cargo.toml
[package]
name = "my-wasm-app"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wit-bindgen = "0.25"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# Build targets
rustup target add wasm32-wasi     # WASI target
rustup target add wasm32-unknown-unknown  # Browser target

# Build
cargo build --target wasm32-wasi --release

# Convert to Component
wasm-tools component new target/wasm32-wasi/release/my_app.wasm \
  -o my_app.component.wasm

8.2 Go - TinyGo

// main.go - TinyGo Wasm
package main

import (
    "encoding/json"
    "net/http"

    spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
)

type Response struct {
    Message string `json:"message"`
    Count   int    `json:"count"`
}

func init() {
    spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
        resp := Response{
            Message: "Hello from Go Wasm!",
            Count:   42,
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(resp)
    })
}

func main() {}
# Build Wasm with TinyGo
tinygo build -target=wasi -o main.wasm main.go

8.3 Python - componentize-py

# app.py - Python Wasm (Spin)
from spin_sdk.http import IncomingHandler, Request, Response
import json

class IncomingHandler(IncomingHandler):
    def handle_request(self, request: Request) -> Response:
        if request.method == "GET" and request.uri == "/api/hello":
            body = json.dumps({
                "message": "Hello from Python Wasm!",
                "path": request.uri,
            })
            return Response(
                200,
                {"content-type": "application/json"},
                bytes(body, "utf-8")
            )

        return Response(404, {}, b"Not found")
# Python -> Wasm component
componentize-py -d spin-http.wit -w spin-http-trigger app -o app.wasm

8.4 JavaScript - jco

// app.js - JavaScript Wasm Component
import { handle } from 'wasi:http/incoming-handler@0.2.0';

export const incomingHandler = {
  handle(request, responseOut) {
    const headers = new Headers();
    headers.set('Content-Type', 'application/json');

    const body = JSON.stringify({
      message: 'Hello from JS Wasm!',
      method: request.method(),
      path: request.pathWithQuery(),
    });

    const response = new OutgoingResponse(headers);
    response.setStatusCode(200);

    const bodyStream = response.body();
    bodyStream.write(new TextEncoder().encode(body));
    bodyStream.close();

    responseOut.set(response);
  }
};
# JavaScript -> Wasm Component
jco componentize app.js -w wasi-http.wit -o app.wasm

8.5 Language Support Comparison

LanguageWasm MaturityWASI SupportComponent ModelBinary SizeNotes
RustVery HighFullFull1-5MBFirst-class citizen
C/C++HighFullPartial0.5-3MBEmscripten
Go (TinyGo)MediumFullFull2-10MBSome std Go unsupported
PythonMediumFullFull10-30MBcomponentize-py
JavaScriptMediumFullFull5-15MBjco
C# (.NET)MediumPartialEarly10-50MBNativeAOT-LLVM
SwiftEarlyPartialEarly5-20MBSwiftWasm
KotlinEarlyPartialEarly10-30MBKotlin/Wasm

9. Performance Comparison

9.1 Cold Start Comparison

PlatformCold StartMemory UsageNotes
Wasm (Spin)0.5-1ms2-10MBMicrosecond level
Wasm (wasmtime)1-5ms5-20MBGeneral purpose
Lambda (Python)150-300ms50-128MBSlower with VPC
Lambda (Java)800-3000ms128-512MBImprovable with SnapStart
Docker Container500-5000ms50MB-1GBImage size dependent
Cloud Run300-2000ms128MB-8GBInstance type dependent

9.2 Throughput Comparison

HTTP "Hello World" benchmark (single instance):

Spin (Rust/Wasm):     ~150,000 req/s
Native Rust (Actix):  ~200,000 req/s
Go (net/http):        ~120,000 req/s
Node.js (Express):    ~30,000 req/s
Python (FastAPI):     ~10,000 req/s

Wasm achieves 70-90% of native performance

9.3 Memory Efficiency

Single HTTP service memory usage:

Wasm (Spin):          2-5 MB
Wasm (wasmtime):      5-15 MB
Node.js:              30-80 MB
Python:               30-60 MB
Java (JVM):           100-300 MB
.NET:                 50-150 MB
Go:                   10-30 MB

Concurrent services in 1GB memory:
Wasm: ~200 services
Node.js: ~15 services
Java: ~5 services

10. Security Model

10.1 Wasm Sandbox

Traditional Process:
+------------------------------------------+
| Process                                  |
|  - Full filesystem access                |
|  - All network access                    |
|  - Unlimited system calls                |
|  - Other process memory (via exploit)    |
+------------------------------------------+

Wasm Sandbox:
+------------------------------------------+
| Wasm Module                              |
|  +------------------------------------+  |
|  | Linear Memory (module-private)      |  |
|  | - Bounds checking                   |  |
|  | - No host memory access             |  |
|  +------------------------------------+  |
|  | Only permitted system interfaces    |  |
|  | - wasi:filesystem (specific paths)  |  |
|  | - wasi:sockets (specific addresses) |  |
|  +------------------------------------+  |
+------------------------------------------+

10.2 Capability-Based Security Principles

PrincipleDescriptionExample
No Ambient AuthorityNo default permissionsNo filesystem or network access
Principle of Least PrivilegeGrant only minimal permissionsOnly specific directory access
Explicit Capability PassingExplicit permission transferHost passes handles
RevocablePermissions can be revokedRuntime permission removal

10.3 Security Comparison

Security AspectContainersWasm
Isolation LevelOS level (cgroup/namespace)Language level (bytecode verification)
Memory SafetyDepends on kernelBuilt-in bounds checking
System CallsFiltered via seccompLimited via WASI
Escape PotentialPossible via kernel vulnerabilityExtremely difficult
Permission ModelUser/group basedCapability based
Code VerificationNoneVerified at load time

11. Real-World Use Cases

11.1 Plugin Systems

// Host application - plugin loader
use wasmtime::*;
use wasmtime_wasi::WasiCtxBuilder;

fn load_plugin(plugin_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let engine = Engine::default();
    let mut linker = Linker::new(&engine);
    wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;

    // Grant minimal permissions to plugin
    let wasi = WasiCtxBuilder::new()
        .inherit_stdout()  // Only stdout allowed
        // No filesystem access
        // No network access
        .build();

    let mut store = Store::new(&engine, wasi);
    let module = Module::from_file(&engine, plugin_path)?;
    let instance = linker.instantiate(&mut store, &module)?;

    // Call plugin function
    let process = instance
        .get_typed_func::<(i32,), i32>(&mut store, "process")?;
    let result = process.call(&mut store, (42,))?;

    println!("Plugin result: {}", result);
    Ok(())
}

11.2 Edge Computing

Edge Wasm Architecture:

User Request -> [CDN Edge (300+ PoPs)]
                  |
                  v
               [Wasm Worker]
                  |
                  +-> Cache Hit: Instant response (0ms)
                  |
                  +-> Cache Miss: Request to origin server
                  |               |
                  |               v
                  |          [Origin Server]
                  |               |
                  v               v
               [Response + Cache Store]

Benefits:
- Executes at the location closest to the user
- Nearly zero cold start
- Automatic global distributed deployment

11.3 Serverless Functions

Lambda vs Wasm Serverless:

AWS Lambda:
  Request -> API Gateway -> Lambda Runtime -> Function Execution
  Cold Start: 100ms-8s
  Memory: 128MB-10GB
  Billing: Per 1ms

Wasm Serverless (Spin/Fermyon):
  Request -> Spin Runtime -> Wasm Module Execution
  Cold Start: Sub-0.5ms
  Memory: 2-50MB
  Billing: Per request

11.4 Blockchain Smart Contracts

Multiple blockchains have adopted Wasm as their smart contract execution engine.

BlockchainWasm RuntimeLanguage Support
PolkadotSubstrateRust (ink!)
NearWasmerRust, AssemblyScript
Cosmos (CosmWasm)WasmerRust
Dfinity (ICP)CustomRust, Motoko

12. Wasm vs Containers

12.1 Comprehensive Comparison

FeatureWasmContainers
Startup TimeMicroseconds-millisecondsMilliseconds-seconds
Image Size1-50MB50MB-GBs
Memory Usage1-50MB50MB-GBs
CPU Overhead0-30%0-5%
SecurityStrong sandboxOS-level isolation
NetworkingWASI (limited)Full support
FilesystemWASI (limited)Full support
GPU SupportExperimentalFull support
EcosystemGrowingVery mature
DebuggingEvolvingMature
State ManagementStateless recommendedStateful possible

12.2 When to Choose Wasm

Choose Wasm when:

  • Sub-millisecond cold starts needed
  • Ultra-lightweight services required
  • Building plugin/extension systems
  • Edge computing
  • Multi-language module composition
  • Strong sandbox isolation needed
  • Resource-constrained environments (IoT)

Choose Containers when:

  • Complex networking required
  • GPU usage needed
  • Legacy application support
  • Rich ecosystem needed
  • State preservation required
  • Large memory/storage needs

13. Future Outlook

13.1 In-Progress Wasm Proposals

ProposalStatusDescription
GC (Garbage Collection)Phase 4Support for Java, Kotlin, Dart GC languages
ThreadsPhase 3Shared memory multithreading
SIMDPhase 4 (Complete)128-bit SIMD operations
Exception HandlingPhase 4Native try/catch support
Stack SwitchingPhase 2Coroutines, async/await support
Memory64Phase 364-bit memory addressing
Branch HintingPhase 3Branch prediction hints
Tail CallPhase 4 (Complete)Tail call optimization

13.2 Wasm Future Roadmap

2025-2026 Outlook:
- WASI 0.2 fully stabilized and adopted by major clouds
- Component Model ecosystem matures
- Docker Wasm production-ready
- GC proposal implemented in major runtimes
- Threads proposal stabilized

2027+ Outlook:
- Wasm reaches parity with containers
- Default runtime for edge-first architectures
- Standard execution environment for IoT/embedded
- Multi-language component ecosystem established

14. Quiz

Q1. What is the core security model of WASI?

Answer: Capability-Based Security

WASI follows the "No Ambient Authority" principle. Wasm modules have no permissions by default, and can only use capabilities (file handles, network sockets, etc.) explicitly granted by the host. This contrasts with the traditional Unix ambient authority model.

Q2. What are the advantages of the Wasm Component Model?

Answer:

  • Language-independent composition: Combine modules written in Rust, Python, Go, etc. into one application
  • WIT interfaces: Type-safe contracts for inter-module communication
  • Sandbox isolation: Each component has its own memory space
  • Lightweight: Tens of times lighter than containers
Q3. Why are Wasm cold starts faster than Lambda?

Answer:

  • Wasm binaries are very small (1-10MB), making loading fast
  • Runtime initialization is at the microsecond level (no heavy initialization like JVM or Python interpreter)
  • AOT-compiled binaries execute directly
  • Linear memory model allows simple memory setup
  • No process/container creation overhead
Q4. How does Docker + Wasm work?

Answer:

Docker Desktop uses containerd's runwasi shim to run Wasm containers. Instead of the traditional runc, Wasm runtimes like wasmtime or wasmedge execute the container. Ultra-lightweight images can be built with a FROM scratch base containing only the .wasm file, and docker-compose can mix Linux containers and Wasm containers.

Q5. Why can Wasm not yet replace containers?

Answer:

  • WASI system interfaces are still limited (GPU, complex networking, etc.)
  • Ecosystem is immature compared to containers
  • Migrating legacy applications is difficult
  • State management is fundamentally stateless
  • Debugging tools are still evolving
  • Some languages have only early-stage Wasm support

However, Wasm is not meant to "replace" containers but rather to "complement" them, coexisting with containers in edge and lightweight service domains.


15. References

  1. WebAssembly Official Site - https://webassembly.org/
  2. WASI Official Documentation - https://wasi.dev/
  3. Component Model Specification - https://component-model.bytecodealliance.org/
  4. Fermyon Spin Documentation - https://developer.fermyon.com/spin/
  5. wasmCloud Documentation - https://wasmcloud.com/docs/
  6. Bytecode Alliance - https://bytecodealliance.org/
  7. wasmtime Runtime - https://wasmtime.dev/
  8. Docker Wasm Guide - https://docs.docker.com/desktop/wasm/
  9. Cloudflare Workers - https://developers.cloudflare.com/workers/
  10. Fastly Compute - https://developer.fastly.com/learning/compute/
  11. wasm-tools - https://github.com/bytecodealliance/wasm-tools
  12. WIT Specification - https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md
  13. componentize-py - https://github.com/bytecodealliance/componentize-py