- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며 — 브라우저는 시작이었을 뿐
- 세 가지 성질 — 왜 WASM이 범용 런타임인가
- WASI — WASM이 시스템과 대화하는 법
- 엣지와 서버리스 — 컨테이너를 위협하다
- 플러그인 시스템 — WASM이 정답이 되는 곳
- 컴포넌트 모델 — 모듈을 넘어서
- 왜 이것이 범용 런타임인가 — 큰 그림
- 냉정한 현실 — 아직 남은 과제들
- 마치며 — 런타임의 재발명
- 참고 자료
들어가며 — 브라우저는 시작이었을 뿐
WebAssembly(줄여서 WASM)를 처음 들으면 대개 "브라우저에서 C++을 돌리는 기술" 정도로 이해합니다. 틀린 말은 아닙니다. WASM은 실제로 브라우저에서 태어났고, 자바스크립트로는 벅찬 무거운 연산을 웹에서 가능하게 하려고 만들어졌습니다.
하지만 WASM의 진짜 야심은 브라우저 밖에 있습니다. 곰곰이 생각해 보면 WASM이 브라우저에서 해결한 문제(안전하게 격리되고, 어떤 언어로든 컴파일되며, 근접 네이티브 속도로 도는 이식 가능한 바이너리)는 브라우저와 아무 상관이 없는 성질입니다. 이 성질들은 서버에서도, 엣지에서도, 플러그인 시스템에서도 똑같이 매력적입니다.
이 글은 브라우저를 떠난 WebAssembly를 다룹니다. WASM이 시스템과 대화하기 위해 만든 WASI라는 인터페이스, 엣지와 서버리스에서 WASM이 왜 컨테이너를 위협하는지, 플러그인 시스템에서 왜 WASM이 정답이 되어 가는지, 그리고 컴포넌트 모델이 이 모든 것을 어떻게 하나로 엮는지를 봅니다. WASM이 어떻게 근접 네이티브 속도를 내는지 그 원리를 브라우저에서 직접 실습하고 싶다면 WASM 원리 실습이 좋은 출발점이고, WAT(WebAssembly 텍스트)를 손으로 짜서 바이너리로 컴파일해 보고 싶다면 WebAssembly 스튜디오에서 실험할 수 있습니다.
세 가지 성질 — 왜 WASM이 범용 런타임인가
WASM이 브라우저를 넘어 확장되는 근본 이유는 세 가지 성질에 있습니다. 이 셋은 원래 브라우저를 위해 설계되었지만, 알고 보니 훨씬 넓은 곳에서 통하는 보편적인 미덕이었습니다.
- 근접 네이티브 속도: WASM은 사전 컴파일된 저수준 바이트코드라, 파싱이 빠르고 JIT/AOT로 기계어에 가깝게 실행됩니다. 인터프리터 언어처럼 느리지 않으면서, 배포는 소스가 아닌 이식 가능한 바이너리로 합니다.
- 샌드박스 격리: WASM 모듈은 기본적으로 아무것도 할 수 없는 상태로 시작합니다. 메모리는 자기 선형 메모리에 갇혀 있고, 시스템 자원에는 호스트가 명시적으로 넘겨준 것만 접근합니다. 신뢰할 수 없는 코드를 돌리기에 이보다 좋은 출발점이 없습니다.
- 이식성: WASM 바이트코드는 CPU 아키텍처(x86, ARM 등)와 무관합니다. 한 번 컴파일한
.wasm을 어느 아키텍처, 어느 운영체제의 WASM 런타임에서든 그대로 돌립니다. "한 번 빌드해 어디서나 실행"의 오랜 꿈에 상당히 가까운 형태입니다.
이 세 성질을 나란히 놓고 보면, 이것이 왜 강력한 조합인지 드러납니다. 컨테이너는 격리와 이식성을 주지만 무겁고 느리게 뜹니다. 네이티브 바이너리는 빠르지만 격리가 약하고 아키텍처에 묶입니다. 인터프리터 언어는 이식성이 좋지만 느립니다. WASM은 이 셋의 좋은 점(빠름, 안전함, 이식 가능함)을 한 봉투에 담으려는 시도입니다. 이 조합이 통하는 곳이 브라우저만은 아니라는 것이 핵심입니다.
WASI — WASM이 시스템과 대화하는 법
여기서 근본적인 문제가 하나 있습니다. WASM 모듈은 기본적으로 아무것도 할 수 없습니다. 파일을 읽을 수도, 네트워크에 접속할 수도, 시계를 볼 수도 없습니다. 브라우저에서는 이게 문제가 안 됩니다. 자바스크립트가 필요한 기능을 다 넘겨주니까요. 그런데 브라우저 밖에서는? 자바스크립트가 없는 서버에서 WASM이 파일 하나 읽으려면 무엇에 기대야 할까요?
이 공백을 메우는 것이 WASI(WebAssembly System Interface)입니다. WASI는 WASM 모듈이 시스템 자원에 접근하기 위한 표준화된 인터페이스, 말하자면 POSIX 비슷한 시스템 콜 규약입니다. 파일 열기, 읽기, 쓰기, 시계 읽기, 난수 얻기 같은 기본 기능을 WASM 모듈이 호출할 수 있는 표준 함수로 정의합니다.
핵심은 WASI가 능력 기반 보안(capability-based security) 모델을 따른다는 점입니다. 전통적인 프로그램은 실행되는 순간 그 사용자가 접근할 수 있는 모든 파일에 접근할 수 있습니다. WASI 모듈은 다릅니다. 기본적으로 아무 파일에도 접근할 수 없고, 호스트가 명시적으로 넘겨준 디렉터리나 파일 핸들만 쓸 수 있습니다.
전통적 프로세스:
실행 = "이 사용자가 가진 모든 권한을 그대로 상속"
(프로그램이 마음대로 파일 시스템 전체를 뒤질 수 있음)
WASI 모듈:
실행 = "아무 권한도 없이 시작"
호스트가 넘겨준 것만 사용 가능
(예: "이 한 디렉터리만 읽어라" — 나머지는 존재하지도 않음)
이 모델의 함의는 큽니다. WASM 모듈에게 딱 필요한 능력만 주고 나머지는 아예 안 보이게 할 수 있습니다. 신뢰할 수 없는 코드를 돌릴 때, "이 프로그램이 실수로든 악의로든 뭘 건드릴 수 있나"라는 걱정이 근본적으로 줄어듭니다. 격리가 "기본 차단, 명시적 허용"이라는 안전한 방향으로 뒤집혀 있기 때문입니다.
WASI는 계속 진화하고 있습니다. 초기 WASI가 파일과 표준 입출력 같은 기본에 집중했다면, 이후 버전은 네트워킹, 비동기 I/O 같은 더 풍부한 기능으로 범위를 넓히고 있습니다. 이 진화의 방향이 뒤에서 다룰 컴포넌트 모델과 맞물립니다.
엣지와 서버리스 — 컨테이너를 위협하다
WASM이 브라우저 밖에서 가장 뜨겁게 쓰이는 곳이 엣지 컴퓨팅과 서버리스입니다. Fastly의 Compute, Cloudflare Workers 같은 플랫폼이 WASM을 실행 단위로 채택하면서, "요청을 어떻게 처리하는가"의 판이 바뀌고 있습니다.
왜 하필 WASM일까요? 서버리스와 엣지의 핵심 과제는 콜드 스타트입니다. 요청이 왔을 때 코드를 실행할 환경을 얼마나 빨리 띄우느냐가 관건입니다. 여기서 컨테이너와 WASM의 차이가 극명합니다.
- 컨테이너: 격리를 위해 리눅스 네임스페이스, cgroup, 파일 시스템 레이어를 세팅합니다. 가볍다고는 해도 콜드 스타트가 수백 밀리초에서 초 단위가 될 수 있습니다.
- WASM 모듈: 이미 샌드박스가 언어 차원에서 보장되므로, 무거운 OS 수준 격리를 세팅할 필요가 없습니다. 인스턴스 생성이 극도로 가벼워 콜드 스타트가 밀리초 이하로 내려갑니다.
이 차이가 만드는 결과가 큽니다. 콜드 스타트가 사실상 사라지면, 요청마다 새 인스턴스를 띄우는 것이 부담이 아니게 됩니다. 그러면 요청을 사용자와 가장 가까운 엣지 노드에서, 필요할 때만 순식간에 띄워 처리하고 버리는 모델이 현실적이 됩니다. 각 엣지 노드에 무거운 컨테이너 오케스트레이션을 깔 필요 없이, 가벼운 WASM 런타임 하나로 수많은 테넌트의 코드를 안전하게 격리해 돌릴 수 있습니다.
밀도(density) 측면도 중요합니다. WASM 인스턴스는 컨테이너보다 훨씬 가볍기 때문에, 같은 하드웨어에서 훨씬 많은 인스턴스를 동시에 돌릴 수 있습니다. 엣지처럼 자원이 제한된 환경에서 이 밀도는 곧 경제성입니다. 하나의 프로세스 안에서 수천 개의 격리된 WASM 인스턴스를 돌리는 것이, 수천 개의 컨테이너를 돌리는 것보다 훨씬 값쌉니다.
물론 트레이드오프도 있습니다. WASM/WASI 환경은 완전한 리눅스가 아니므로, 기존 컨테이너 이미지를 그대로 옮길 수는 없습니다. 애플리케이션이 WASI가 아직 지원하지 않는 시스템 기능에 의존하면 곤란해집니다. 즉 엣지 WASM은 "가볍고 빠르지만 제한된" 환경이고, 완전한 OS가 필요한 워크로드에는 여전히 컨테이너가 맞습니다.
플러그인 시스템 — WASM이 정답이 되는 곳
WASM이 조용히, 그러나 결정적으로 자리 잡고 있는 또 다른 영역이 플러그인 시스템입니다. 어떤 애플리케이션에 제3자가 만든 코드를 안전하게 끼워 넣고 싶을 때, WASM은 거의 이상적인 답이 됩니다.
플러그인의 오래된 딜레마를 생각해 봅시다. 플러그인은 강력해야 유용하지만, 강력할수록 위험합니다. 네이티브 플러그인(예: 공유 라이브러리)은 호스트 프로세스와 같은 주소 공간에서 돌기 때문에, 버그 하나가 호스트 전체를 죽이고 악의적 플러그인이 뭐든 할 수 있습니다. 반대로 플러그인을 별도 프로세스로 격리하면 안전하지만 느리고 복잡해집니다.
WASM은 이 딜레마를 깔끔하게 풉니다. 플러그인을 WASM 모듈로 만들면, 호스트와 같은 프로세스 안에서 빠르게 돌면서도 샌드박스로 격리됩니다. 플러그인은 호스트가 명시적으로 넘겨준 함수만 호출할 수 있고, 호스트의 메모리를 함부로 건드릴 수 없습니다. 게다가 어떤 언어로든 플러그인을 작성할 수 있으니, 플러그인 개발자가 호스트와 같은 언어를 쓸 필요도 없습니다.
실제 사례들이 이 방향을 증명합니다.
- Envoy 프록시: 네트워크 프록시 Envoy는 WASM으로 필터를 확장할 수 있게 했습니다. 트래픽을 가로채 조작하는 커스텀 로직을, 프록시를 다시 컴파일하지 않고 WASM 모듈로 주입합니다. 이 확장 규약이 발전해 프록시-WASM이라는 인터페이스로 표준화되었습니다.
- Figma: 디자인 도구 Figma는 플러그인을 샌드박스에서 안전하게 돌리기 위해 WASM 기반 접근을 활용합니다. 제3자 플러그인이 사용자의 디자인 데이터를 다루면서도, 그 실행을 안전하게 가둡니다.
- 데이터베이스: 여러 현대 데이터베이스가 사용자 정의 함수(UDF)나 확장을 WASM으로 실행하는 방향을 탐색합니다. 사용자가 작성한 코드를 데이터베이스 프로세스 안에서 돌리는 것은 전통적으로 극도로 위험했는데, WASM 샌드박스가 이를 안전하게 만듭니다.
이 사례들의 공통점은 "신뢰할 수 없는 확장 코드를, 호스트를 위협하지 않으면서, 빠르게 실행"해야 한다는 요구입니다. 이것이 정확히 WASM의 세 성질(빠름·안전함·언어 무관)이 빛나는 지점입니다. 플러그인 시스템을 새로 설계하는 사람이라면, 이제 WASM을 진지하게 후보로 올릴 만합니다.
컴포넌트 모델 — 모듈을 넘어서
지금까지 이야기한 WASM은 대개 "모듈"이라는 단위였습니다. 하지만 순수 WASM 모듈에는 실무에서 아픈 한계가 있습니다. 모듈 간에, 혹은 모듈과 호스트 간에 주고받을 수 있는 것이 기본적으로 숫자(정수와 부동소수점)뿐이라는 것입니다. 문자열 하나, 리스트 하나, 구조체 하나를 넘기려 해도 표준화된 방법이 없어서, 각자 메모리 포인터와 길이를 주고받는 저수준 규약을 손으로 맞춰야 했습니다.
이 문제를 푸는 것이 컴포넌트 모델(Component Model)입니다. 컴포넌트 모델은 WASM 모듈 위에 고수준 타입 시스템과 인터페이스 정의를 얹습니다. 문자열, 리스트, 레코드, 배리언트 같은 풍부한 타입을 인터페이스 수준에서 정의하고, 서로 다른 언어로 짠 컴포넌트들이 이 타입을 통해 자연스럽게 통신하게 합니다.
핵심 아이디어를 정리하면 이렇습니다.
- 인터페이스를 언어 중립적으로 기술한다: WIT(WebAssembly Interface Types)라는 언어로 "이 컴포넌트는 이런 함수를 제공하고, 이런 타입을 주고받는다"를 선언합니다. 이 기술은 특정 언어에 묶이지 않습니다.
- 언어 간 조합이 자연스러워진다: Rust로 짠 컴포넌트와 Go로 짠 컴포넌트가, 서로의 내부 메모리 표현을 몰라도 인터페이스 타입을 통해 안전하게 값을 주고받습니다. 문자열은 문자열로, 리스트는 리스트로 오갑니다.
- 재사용과 조립이 쉬워진다: 컴포넌트를 레고 블록처럼 조합할 수 있습니다. 한 컴포넌트의 출력을 다른 컴포넌트의 입력으로 연결하고, 필요한 부분만 갈아 끼웁니다.
컴포넌트 모델이 중요한 이유는, 이것이 WASM을 "브라우저에서 C++ 돌리는 기술"에서 "언어 중립적인 소프트웨어 조립 규격"으로 승격시키기 때문입니다. 앞서 본 WASI의 최신 방향도 이 컴포넌트 모델 위에서 정의됩니다. 즉 시스템 인터페이스마저 컴포넌트 인터페이스로 표현되어, 플랫폼이 제공하는 능력과 모듈이 요구하는 능력이 같은 타입 언어로 맞물립니다.
왜 이것이 범용 런타임인가 — 큰 그림
지금까지의 조각들을 하나로 모아 봅시다. WASM은 근접 네이티브 속도로 돌고, 언어에 무관하며, 강하게 샌드박스되고, 아키텍처에 이식 가능합니다. WASI가 시스템 접근을 능력 기반으로 표준화하고, 컴포넌트 모델이 언어 간 조립을 가능하게 합니다. 이 그림을 멀리서 보면 익숙한 무언가가 떠오릅니다. 바로 "범용 런타임"의 윤곽입니다.
역사적으로 우리는 "한 번 짜서 어디서나 돌린다"는 꿈을 여러 번 좇았습니다. 그때마다 대가가 있었습니다. 이식성을 얻으려고 무거운 런타임을 깔거나, 성능을 포기하거나, 특정 언어에 갇혔습니다. WASM이 흥미로운 것은 이 대가들을 동시에 줄이려 한다는 점입니다.
- 컨테이너보다 가볍다: OS 수준 격리 없이 언어 차원에서 격리하므로, 콜드 스타트와 밀도에서 유리합니다.
- 언어 런타임보다 이식적이다: 특정 언어 VM에 묶이지 않고, 어떤 언어든 컴파일해 넣을 수 있습니다.
- 네이티브보다 안전하다: 샌드박스가 기본이라, 신뢰할 수 없는 코드를 돌리기에 적합합니다.
이것이 WASM이 브라우저를 넘어 서버, 엣지, 플러그인, 심지어 IoT까지 번져 나가는 이유입니다. "안전하게 격리된, 빠르고 이식 가능한 코드 실행 단위"라는 필요는 어디에나 있고, WASM은 그 필요에 대한 상당히 좋은 답이기 때문입니다.
냉정한 현실 — 아직 남은 과제들
물론 WASM이 모든 것을 정복했다는 식의 이야기는 과장입니다. 브라우저 밖 WASM에는 여전히 성숙 중인 부분이 많습니다.
- 생태계 성숙도: 컨테이너 생태계는 수년간 다져진 방대한 도구, 레지스트리, 운영 노하우를 갖췄습니다. WASM 쪽은 빠르게 발전하지만 아직 그만큼 두텁지 않습니다. 프로덕션 운영에 필요한 관측성, 디버깅, 배포 도구가 계속 채워지는 중입니다.
- WASI의 표준화 진행 중: 네트워킹, 비동기, 파일 시스템 등 핵심 기능의 표준이 아직 진화하고 있습니다. 표준이 굳어지는 과정이라 버전 간 차이나 미지원 기능에 부딪힐 수 있습니다.
- 언어별 지원 편차: Rust처럼 WASM 타깃이 성숙한 언어가 있는가 하면, 런타임이 무거워 WASM에 잘 안 맞거나 지원이 초기 단계인 언어도 있습니다. 어떤 언어로 무엇을 컴파일하느냐에 따라 경험이 크게 다릅니다.
- 완전한 시스템이 아니다: 앞서 강조했듯, WASM/WASI는 완전한 OS가 아닙니다. 기존 리눅스 애플리케이션을 그대로 옮기려 하면 지원되지 않는 시스템 콜에 막힙니다. WASM은 "새로 그 위에 맞춰 짜는" 환경이지, "기존 것을 그대로 담는" 환경이 아닙니다.
이 과제들을 종합하면, 브라우저 밖 WASM은 "잠재력은 분명하지만 아직 채워지는 중"인 기술입니다. 오늘 당장 모든 컨테이너를 대체하지는 못하지만, 신뢰할 수 없는 코드를 가볍게 격리해야 하는 특정 영역(엣지 함수, 플러그인, 멀티테넌트 실행)에서는 이미 실전에서 우위를 보입니다.
마치며 — 런타임의 재발명
WebAssembly는 브라우저에서 태어났지만, 그것이 진짜로 재발명하고 있는 것은 "코드를 안전하고 빠르게, 어디서나 실행하는 방법" 그 자체입니다. 근접 네이티브 속도, 샌드박스 격리, 아키텍처 이식성이라는 세 성질은 브라우저만의 필요가 아니라 컴퓨팅 어디에나 있는 필요였고, WASM은 그 필요에 하나의 봉투로 답합니다.
WASI가 시스템과의 대화를 능력 기반으로 표준화하고, 엣지와 서버리스가 콜드 스타트의 벽을 허물며, 플러그인 시스템이 신뢰의 딜레마를 풀고, 컴포넌트 모델이 언어의 장벽을 낮춥니다. 이 조각들이 모이면, WASM은 특정 플랫폼의 기술이 아니라 플랫폼을 가로지르는 범용 실행 규격에 가까워집니다.
물론 갈 길은 남았습니다. 생태계는 채워지는 중이고, 표준은 굳어지는 중이며, 완전한 OS를 대체하지도 않습니다. 하지만 방향은 분명합니다. 다음에 "이 신뢰할 수 없는 코드를 어떻게 안전하게 돌리지", "이 로직을 어떻게 여러 언어와 여러 환경에서 재사용하지"를 고민할 일이 생기면, 브라우저 밖의 WebAssembly를 후보 목록에 올려 두시기 바랍니다. 그 목록에서 WASM이 차지하는 자리는 매년 넓어지고 있습니다.
참고 자료
- WebAssembly 공식 사이트: https://webassembly.org/
- WASI: https://wasi.dev/
- 컴포넌트 모델 (WebAssembly): https://component-model.bytecodealliance.org/
- Bytecode Alliance: https://bytecodealliance.org/
- Fastly Compute: https://www.fastly.com/products/compute
- Cloudflare Workers: https://developers.cloudflare.com/workers/
- proxy-wasm (Envoy 확장): https://github.com/proxy-wasm/spec