Wasm은 새로운 CGI
(roborooter.com)- Wasm은 CGI 프로토콜이 아니라
cgi-bin이 만들었던 것처럼 웹 앱의 실행 단위와 배포 방식을 바꿀 다음 애플리케이션 모델로 볼 수 있음 - CGI, FastCGI, Rack/WSGI, 서버리스는 모두 요청 처리와 서버 관리를 다시 설계해 왔고, 공통 목표는 고성능 애플리케이션을 더 쉽게 만들고 유지하는 것이었음
- Wasm 모듈은 호스트 런타임에서 실행되며, 격리된 메모리와 스냅샷을 통해 깨끗한 실행 상태를 유지하면서 시작 비용을 줄일 수 있음
- 네이티브 스레드 부재, JIT 불가, 데이터 복사 비용, Interface Types와 module linking의 미성숙함은 Wasm 기반 서버 실행 모델의 주요 제약임
- 서버리스 함수와 엣지 함수가 Wasm 실행 환경과 결합되면 콜드 스타트와 격리 비용을 낮추고, 여러 언어의 모듈을 더 가볍게 조합할 수 있음
CGI에서 서버리스까지 이어진 웹 애플리케이션 모델
- CGI의 핵심은 Common Gateway Interface 프로토콜 자체보다
cgi-bin폴더에 둔 스크립트나 실행 파일을 URL로 호출하는 애플리케이션 모델에 있었음 - 이 방식은 웹을 문서 아카이브에서 상호작용 가능한 애플리케이션 네트워크로 바꾸는 초기 웹 애플리케이션 모델이었음
- 요청마다 새 프로세스를 실행하는 구조라, 오늘날 기준으로는 프로세스 시작과 스크립트 파싱 비용이 큰 병목이 됨
FastCGI와 언어별 웹 서버의 변화
- FastCGI는 CGI의 성능 문제를 줄이기 위해 오래 살아 있는 프로세스가 CGI 요청을 처리하는 모델을 도입함
- 웹 서버는 요청마다 새 프로세스를 띄우지 않고 하나 이상의 장기 실행 프로세스와 통신함
- 기존 CGI 애플리케이션은 요청 후 프로세스가 종료된다는 가정으로 만들어져, 장기 실행 환경에서 리소스 누수가 생기기 쉬웠음
- 이후 언어 기반 웹 서버가 관례로 자리 잡았고, 애플리케이션은 요청/응답 모델을 중심으로 만들어짐
- Apache나 nginx처럼 기능이 풍부하고 검증된 웹 서버 뒤에 배치해, 느린 요청과 HTTP 세부 사항으로부터 애플리케이션을 분리하는 방식이 일반적이었음
- 서버 구현은 요청마다 fork, OS 또는 언어 스레드, 이벤트 또는 리액터 모델 등 다양한 프로세스 관리 전략을 사용함
- Ruby 커뮤니티의 Rack 인터페이스는 Python의 Flask 애플리케이션 서버와 WSGI 명세에도 영향을 줌
- 단순화하면 요청은 HTTP 메서드, 헤더 해시맵, 입력 바이트 문자열 또는 스트림으로 구성됨
- 응답은 상태 코드, 헤더 객체, 응답 바이트 문자열 또는 스트림으로 구성됨
클라우드 오토스케일링과 서버리스의 절충
- 물리 서버나 가상 서버 기반 모델에서는 실행 중인 서버 수를 직접 관리해야 했음
- 트래픽이 높으면 애플리케이션 서버가 느려질 수 있음
- 트래픽이 낮으면 많은 컴퓨터가 유휴 상태로 남을 수 있음
- 클라우드의 autoscaling은 CPU, 메모리 부하, 시간대에 따라 애플리케이션 서버 수를 조절할 수 있게 함
- 새 컴퓨터를 확장하는 데는 애플리케이션과 설정에 따라 2~20분이 걸릴 수 있음
- 확장은 클라우드 호스팅 리전의 가용 리소스에도 의존함
- Amazon Lambda와 API Gateway를 결합한 서버리스 컴퓨트는 서버 대신 함수를 관리하는 모델을 만들었음
- 요청마다 단일 프로세스, 격리된 CPU, 격리된 메모리를 보장함
- 프로세스는 최대 몇 시간 재사용될 수 있지만 사용하지 않으면 일시 중지되거나 제거됨
- AWS는 요청량에 따라 몇 초 단위로 확장 및 축소할 수 있음
- 서버리스에는 명확한 트레이드오프가 있음
- 새 프로세스 비용 때문에 동시 요청 확장 시 일부 요청이 콜드 스타트를 겪음
- 응답 후 프로세스가 일시 중지될 수 있어 요청 간 지속 TCP 연결 관리가 까다로움
- HTTP 기반 데이터베이스 API는 많은 연결을 견디고 함수와 함께 확장·축소하기 쉬워 서버리스 모델에서 인기가 있음
- 요청마다 전용 CPU와 메모리를 제공하는 특성은 워크로드에 따라 장점도 단점도 됨
- 일부 워크로드는 리소스 관리를 줄이고 비용과 확장 우려를 낮출 수 있음
- 다른 워크로드는 단일 프로세스가 많은 요청을 처리하거나 공유 메모리로 배치·캐싱을 활용할 때 더 효율적일 수 있음
- CMS 기반 웹 애플리케이션을 서버리스로 옮겨 비용을 90% 줄인 사례와, 이벤트 분석 서비스를 서버 기반 모델로 옮겨 비용을 90% 줄인 사례가 함께 제시됨
서버에서의 Wasm 실행 모델
- Wasm은 처음에 브라우저에서 고성능 코드를 실행하기 위해 개발됐고, asm.js 같은 시도와도 연결됨
- WebAssembly는 스택 기반 가상 머신을 위한 바이너리 명령 형식이며, 여러 프로그래밍 언어의 이식 가능한 컴파일 타깃으로 설계됨
- 웹의 클라이언트와 서버 애플리케이션 배포를 가능하게 함
- 크기와 로드 시간에 효율적인 바이너리 형식으로 인코딩되도록 설계됨
- 다양한 플랫폼의 공통 하드웨어 기능을 활용해 네이티브 속도에 가까운 실행을 목표로 함
- 현재는 여러 언어를 Wasm 명령으로 컴파일해 브라우저와 서버 모두에서 실행할 수 있음
- 브라우저가 요구한 격리와 보안 모델은 서버 애플리케이션에도 유용함
- 신뢰할 수 없는 코드를 VM이나 Docker 컨테이너보다 훨씬 가벼운 형태로 격리할 수 있음
- Node.js, Cloudflare Workers, Deno 같은 V8 기반 서버리스 환경은 브라우저에서 축적된 Wasm 실행 역량을 활용함
- Fastly, Shopify, Suborbital 같은 Wasm 네이티브 환경도 존재함
모듈, 호스트, 메모리, 스냅샷
- Wasm 모듈은 가상 머신용 명령이므로 실행을 위해 런타임이 필요함
- 런타임은 일반 Wasm을 로컬 아키텍처에 맞게 컴파일하고 실행 환경을 제공함
- 일부 환경은 Linux 시스템의 POSIX API와 비슷한 인터페이스를 제공함
- 일부 환경은 호스트 시스템의 특정 함수만 제공하고 모듈의 export 함수를 실행하게 함
- WebAssembly 프로그램은 modules 단위로 구성되고, 모듈을 실행하는 VM은 host라고 부름
- 모듈은 배포, 로딩, 컴파일의 단위임
- 타입, 함수, 테이블, 메모리, 전역값 정의를 모음
- import와 export를 선언하고 데이터 세그먼트, 요소 세그먼트, start 함수 형태의 초기화를 제공할 수 있음
- Wasm의 “memories”는 끊김 없는 연속 바이트 배열로 표현되며, 호스트가 인스턴스화 시점에 할당함
- 각 게스트 모듈은 메모리 격리를 얻음
- 이 메모리는 가상 머신의 RAM처럼 동작함
- 비어 있게 제공하거나 데이터 세그먼트로 미리 채울 수 있음
- 모듈 격리 방식 덕분에 모듈을 일시 중지하고 메모리를 데이터 세그먼트로 저장할 수 있음
- 가상 머신 스냅샷과 비슷한 개념임
- 일시 중지된 모듈의 복사본을 여러 개 시작할 수 있음
- Wizer는 Wasm 모듈을 인스턴스화하고 초기화 함수를 실행한 뒤 인스턴스 상태를 기록해 Wasm 바이너리를 다시 작성함
- 전역값의 상태를 직접 초기화함
- 0이 아닌 메모리 영역을 기록함
- 기존 데이터 세그먼트를 제거하고 기록된 메모리 영역에 대한 데이터 세그먼트로 대체함
- 이 방식은 새 프로세스처럼 깨끗한 실행을 제공하면서도 새 프로세스의 시작 비용은 피함
- CGI의 단점 없는 CGI에 가까움
- 최신 표현으로는 콜드 스타트 없는 서버리스에 가까움
Wasm의 제약과 장점
- Wasm은 네이티브 구성으로 스레드를 갖지 않음
- 블로킹 작업은 호스트 메서드로 이동해야 함
- 호스트가 파일이나 네트워크 인터페이스 읽기·쓰기 래퍼를 제공하거나, 모듈을 일시 중지하거나, 콜백 핸들러를 제공할 수 있음
- 리액터 모델이나 블로킹 모델을 만들 수 있지만, thread proposal이 적용되기 전까지는 실행 환경 설계가 큰 비중을 차지함
- 보안상의 이유로 동적 Wasm 코드 생성이 허용되지 않아 JIT 컴파일이 불가능함
- 런타임에서 코드 자체를 주소로 다룰 수 없음
- V8, CRuby 등 JIT에 성능을 의존하는 실행 환경은 Wasm VM에서 실행할 수 없거나 JIT를 포기해야 함
- 스크립트용 최적화 런타임을 빌드 단계에서 출력하는 “pre-jit” 접근이 제안됐지만 널리 쓰이지는 않음
- Wasm 모듈과 호스트의 기본 인터페이스는 메모리이므로 데이터 이동에는 복사가 필요할 수 있음
- 메모리 청크 공유는 가능하지만 런타임의 메모리 모델에 따라 가능 여부나 권장 여부가 달라짐
- 대부분의 런타임에서는 모듈과 I/O 작업 사이에 제로 카피 통신이 어려운 것으로 다뤄짐
- 스트리밍 데이터를 Wasm 모듈 안팎으로 이동하는 작업은 호스트에서 처리하는 것보다 느릴 수 있음
- Wasm VM은 사용량 제어 측면에서 높은 통제를 제공함
- 일부 런타임은 Wasmtime fuel concept처럼 CPU 명령 수를 세어 CPU 한도를 강제할 수 있음
- VM은 메모리와 wall clock 시간을 제한할 수 있음
- Interface Types와 module linking은 모듈 크기를 줄이고 I/O 속도와 사용성을 개선할 수 있음
- Interface Types는 사용할 수 있지만 아직 비준된 표준은 아님
- module linking은 동작하는 프로토타입이 있지만 표준 접근은 아직 없음
- Wizer는 현재 module linking과 충돌할 수 있으며, 이를 해결하는 커스텀 접근은 있지만 명확한 승자는 없음
- Interface Types는 언어 중립 객체가 Wasm 메모리 경계를 비싼 인코딩·디코딩 없이 통과할 수 있게 하는 방향임
- 현재 흔한 방식은 JSON을 메모리에 복사해 넣고 빼는 것임
- Wasm 모듈은 기본적으로 주어진 것에만 접근할 수 있어 보안 모델이 작고 명확함
- 신뢰할 수 없는 Wasm 코드를 실행하는 것은 일반적으로 안전한 편임
- VM의 공격 표면은 Docker나 다른 격리 모델보다 작음
- 호스트 하드웨어에서 변환된 명령을 실행하므로 타이밍 공격은 가능하지만 완화책이 있음
- Wasm을 네이티브 바이너리로 컴파일할 수도 있으나 공격 표면은 더 커짐
엣지 함수와 Wasm 기반 함수 실행
- Wasm 실행 환경과 개발 도구가 널리 쓰이면 스크립트 언어도 Wasm 런타임과 Wizer 같은 사전 부팅(preboot) 방식을 갖추도록 압박받을 수 있음
- 이론적으로 애플리케이션은 요청마다 스냅샷된 복사본에서 재개되어 현재 다른 모델보다 더 빠르게 실행될 수 있음
- 로컬 CLI도 Ruby로 작성한 뒤 스냅샷된 Wasm 모듈로 배포하고 Wasm Ruby 런타임에 연결하면, C++ 유틸리티에 가까운 시작 시간을 얻고 프로젝트 디렉터리 안에서만 동작하도록 제한할 수 있음
- 첫 번째 주요 변화는 함수를 사용자 가까운 엣지로 이동시키는 것임
- 컴퓨트가 데이터베이스 근처가 아니라 사용자 근처에서 수행됨
- Vercel Edge Functions는 V8 기반이지만 여러 원칙을 공유하는 예로 제시됨
- next-auth는 JWT 로그인 토큰을 기반으로 사전 렌더링 페이지 접근을 제어할 수 있음
- CDN에 캐시된 데이터로 구성된 동적 개인화 콘텐츠를 제공할 수 있음
- 또 다른 변화는 서버리스 애플리케이션에서 프로세스 기반 함수를 Wasm 기반 함수로 대체하는 것임
- Suborbital은 Wasm 기반 함수 실행 환경을 직접 만들 수 있게 하고, Wasm 함수를 워크플로로 체인하는 방식도 제공함
- 많은 실행 플랫폼은 요청당 단일 모듈을 권장하며 메모리 공유나 여러 모듈의 빠른 호출 가능성을 충분히 활용하지 않는 것으로 다뤄짐
- Interface Types가 표준화되면 Rack과 비슷한 미들웨어 데이터 모델이 등장할 수 있음
- Wasm은 Lambda 함수 안에서도 실행할 수 있음
- 기존 인프라에서 스냅샷된 애플리케이션 버전을 사용할 수 있음
- 이 조합은 흥미롭지만 결국 사라질 수 있는 기술 혼합으로 다뤄짐
다음 웹 애플리케이션 모델의 방향
- Wasm은 성능을 높이고, 프로세스 수준 보안을 쉽게 만들고, 서버리스 함수의 빌드와 실행 비용을 낮출 수 있는 기술로 제시됨
- 거의 모든 언어를 실행할 수 있고, module linking과 Interface Types를 통해 함수 간 지연 시간을 크게 낮출 수 있음
- 시스템의 제약이 바뀌면 이전에는 불가능했던 일이 가능해진다는 점이 Wasm을 새로운 CGI로 보는 핵심 근거임
댓글과 토론
Hacker News 의견들
-
WASM이 Java Applet, ActiveX, Silverlight, Macromedia Flash 같은 예전 기술과 뭐가 다른지 잘 모르겠음
브라우저에서 신뢰할 수 없는 제3자 컴파일 코드를 실행하는 건 이미 교훈을 얻은 줄 알았고, 고객 경험 개선이라는 명목으로 서버의 계산 비용을 클라이언트로 넘기는 구조처럼 보임- Java와 Flash는 “무엇이든 안전하게 실행할 수 있는 깨지지 않는 샌드박스”라는 약속을 지키지 못했음
구현에 취약점이 많았고 결국 브라우저에서 사실상 못 쓰게 됐으며, 다른 기술들은 애초에 그런 약속조차 하지 않았던 것 같음
JavaScript는 그 약속을 실제로 지켰고, 오늘날 브라우저는 어느 도메인에서 내려받은 JavaScript든 사용자에게 신뢰 여부를 묻지 않고 실행함
WASM은 JavaScript 엔진 위에 올라가 비슷한 보안 보장을 제공하므로 JVM 바이트코드와 근본적 차이는 없고, 실질적 차이는 WASM은 안전성을 입증했고 JVM은 그러지 못했다는 데 있음
이제 Google Chrome은 수십억 명이 악성 WASM을 실행해도 휴대폰이 뚫리지 않을 만큼 안전하고, 이 엔진을 서버로 가져와 여러 사용자의 스크립트를 강한 샌드박스 안에서 실행하며 자원을 공유하게 만들 수 있음
대안은 가상화로, 코드를 WASM 덩어리로 컴파일해 큰 WASM 서버에서 돌리거나 amd64 바이너리와 잘라낸 Linux 커널을 묶어 VM에서 돌릴 수 있음
지금은 어느 쪽이 명확한 승자라고 보기 어렵고 각 접근법마다 장단점이 있음 - ActiveX, Silverlight, Flash와 달리 WASM은 여러 업계 참여자가 만드는 개방형 표준이고 구현도 여러 개라서, 그것만으로도 대안들보다 훨씬 나음
JVM과 달리 WASM은 선형 메모리를 제공하고 기본적으로 가비지 컬렉션이 없어서 C/C++를 Emscripten으로 컴파일하거나 Rust를 대상으로 삼는 등 더 넓은 언어군의 컴파일 대상이 되기 좋음
WASM은 바이트코드이고, 대부분의 구현은 호스트 JavaScript 엔진과 런타임을 많이 공유한다고 봄
클라이언트와 서버 사이의 계산 비용 이동은 업계가 오래전부터 두꺼운 클라이언트와 얇은 클라이언트 사이를 오간 흐름의 일부이고, 이 진자는 앞으로도 계속 움직일 것임 - Wasm은 예전 기술들보다 장점이 큼
Wasm 바이트코드가 따라야 하는 검증 명세가 있고, 이 검증된 부분집합 덕분에 과거 기술에서 보던 보안 취약점 상당수가 원천적으로 불가능해짐
Heartbleed나 Rowhammer처럼 하드웨어 오동작에 기대는 공격은 가능할 수 있지만, 예를 들어 숫자를 포인터처럼 해석하도록 VM을 속여 자기 Wasm 메모리 밖을 참조하는 식은 할 수 없음
Wasm 바이트코드는 기계어로 바꾸기 매우 단순한 편이라 VM을 쓰는 것보다 구현이 작고 빠를 수 있음
특정 회사 소유가 아니고 누구나 사용할 수 있는 잘 쓰인 공개 명세가 있으며, 웹 표준으로 채택되어 브라우저 확장이 필요 없음
클라이언트 계산은 이미 JavaScript에서도 일어나는 일이고, Wasm 코드는 JavaScript로는 불가능한 방식으로 효율적일 수 있어서 오히려 더 그렇다 - Java Applet과 ActiveX는 하위 운영체제에 대한 접근이 덜 중재됐음
Applet은 어느 정도, ActiveX는 거의 전혀 중재되지 않았고, WASM의 “바깥 플랫폼”은 대략 JavaScript 런타임인 반면 Applet의 바깥 플랫폼은 execve(2) 에 가까움 - 이 글은 서버에서의 WASM을 다루므로, 서버 계산 비용을 클라이언트로 넘기는 얘기와는 다름
WASM은 그럴 수도 있지만 항상 그런 것은 아니고, 더 나은 샌드박싱과 격리 같은 차이도 이미 다른 답변들이 잘 다뤘음
- Java와 Flash는 “무엇이든 안전하게 실행할 수 있는 깨지지 않는 샌드박스”라는 약속을 지키지 못했음
-
“Amazon이 Lambda로 서버리스 컴퓨팅 시대를 열었다”기에는 Google App Engine이 2008년에 나와 Lambda보다 6년 앞섰음
- Heroku와 그 세대의 PaaS도 있었음
이미 몇 년 전부터 그런 제품들이 있었고 이름도 있었는데 왜 “serverless”라는 이름이 붙었는지, 어디서 온 건지 잘 모르겠음
App Engine에도 배치 워커와 웹 워커가 있었고 Heroku도 마찬가지였음
둘 다 Docker 이전 제품이라 사람들이 다르게 느끼는 걸 수도 있지만, Lambda도 처음부터 Docker로 출시된 건 아니었던 것 같음
- Heroku와 그 세대의 PaaS도 있었음
-
“보안상의 이유로 동적 Wasm 코드 생성이 허용되지 않아 JIT 컴파일이 불가능하다”는 말은 맞지 않아 보임
깨끗한 코드 핫 리로딩 같은 작업을 허용하려면 본질적인 기능에 가까움
보안 논리는 허술하다고 봄
JS는 실행 중 핫 리로드나 더 과격한 코드 생성도 보안을 깨지 않고 할 수 있고, Wasm 런타임 전체를 동적으로 다시 로드하면서 메모리를 보존하면 코드 생성이나 핫 리로드를 흉내 낼 수도 있지만 사용자 경험은 투박해질 것임
기술적으로 불가능해야 할 이유가 보이지 않고, 보안 조치라면 너무 쉽게 우회 가능해 보임
WASM 바이트코드는 개념적으로 .NET IL이나 Java 바이트코드처럼 JIT 컴파일을 염두에 둔 것들과 매우 비슷함
WASM은 강한 방향성과 제때 성공시키려는 의지가 부족한 프로젝트 같아서 별로 좋아하지 않음
이름은 “웹용 어셈블리”, 즉 가상 CPU용 기계어를 암시하지만 실제로는 컴파일러 백엔드를 위한 중간 표현이고, 가비지 컬렉션 지원 같은 고수준 기능도 계획되어 있어 개념이 불명확함
앞서 말한 핫 리로드, 해킹에 가깝지 않은 스레딩, JavaScript 없이 DOM과 직접 연동, 낮은 오버헤드의 그래픽/계산 API, 저수준 오디오 접근 같은 기본 기능도 아직 부족함
큰 멀티미디어 앱을 큰 타협 없이 돌리기는 어렵다- 그 문장은 맞음
Wasm은 메모리를 실행 가능으로 표시할 수 없고 사실상 하버드 구조처럼 코드와 메모리가 분리되어 있음
더구나 코드의 임의 위치로 점프할 수도 없고, 점프 명령 자체도 없음
여기서 JIT는 실행 중 네이티브 코드를 컴파일하고 실행하는 것을 뜻하며, 브라우저나 Wasm 샌드박스에서는 큰 보안 약점이 됨
이건 설계와 명령어 집합에 박혀 있어서 쉽게 우회되는 성질이 아니며, 자세한 내용은 https://webassembly.org/docs/security/에서 볼 수 있음
Wasm도 엔진이 JIT를 담당한다는 점에서는 .NET IL이나 Java 바이트코드와 비슷하지만, 사용자에게 런타임을 벗어나 네이티브 코드를 만들고 그곳으로 점프할 권한을 주는 건 위험함 - 브라우저는 WASM에 대해 분명 어떤 형태의 JIT를 사용함
그래서 JIT와 마찬가지로 WASM 코드를 처음 실행할 때 약간의 “워밍업 끊김”이 보일 수 있는데, 몇 년 사이 훨씬 나아졌음
또한 브라우저에서 WASM 덩어리를 동적으로 만들고 인스턴스화해 실행할 수 있는 걸로 알고 있음
다른 WASM 런타임에서도 가능한지는 모르겠고, 브라우저에서도 JavaScript를 거쳐야 하지만 어떤 “웹 API”에 접근하려 해도 어차피 그게 필요함
- 그 문장은 맞음
-
WASM은 JavaScript VM처럼 특정 언어 전용인 VM을, JavaScript VM이 쓰이는 곳 어디서나 사용할 수 있는 범용 VM으로 바꾸는 것임
물론 그곳에만 한정되지는 않음
범용이라는 말은 컴파일러나 인터프리터만 있으면 거의 무엇이든 실행할 수 있다는 뜻이고, JavaScript도 포함됨
대체로 JavaScript 엔진의 일부로 구현되므로 샌드박싱과 해당 API 접근 같은 특성을 많이 물려받음
그 접근을 표준화하는 일은 아직 진행 중이지만, 최종적으로는 현재 JavaScript로만 가능한 일들이 WASM에서도 가능해지고, JavaScript로 어렵거나 불가능한 더 많은 일도 가능해질 것임
더 빠르고 매끄럽게 실행될 수도 있음
WASM의 핵심은 JavaScript가 인기 있는 환경에 있던 제약을 많이 제거하는 데 있음
JavaScript는 호불호가 큰 언어라, 유일한 선택지에서 여러 선택지 중 하나로 바뀌는 셈임
WASM은 JavaScript 대체재, Docker 대체재, Java 대체재, CGI 대체재로도 묘사되어 왔고, 짧게 말하면 이 모든 것이면서 그 이상임- JavaScript 자체에는 불만이 없지만, 웹에 JS를 배포하는 생태계가 문제라고 봄
비슷한 일을 하는 도구가 너무 많고 경계가 불분명함
결국 다 동작하게 만들어도 개인적으로는 취약하게 느껴지고, 전문적으로 하지 않는 사람에게는 겁나는 일임
요즘 웹용으로 뭔가를 만들어야 할 때는 leptos를 쓰는데 개발자 경험이 훨씬 좋고, 아직 1.x도 아니지만 JS 번들을 트랜스파일하고 난독화하고 축소하고 패킹하려고 도구 5개를 이어 붙이는 것보다 안정적으로 느껴짐
- JavaScript 자체에는 불만이 없지만, 웹에 JS를 배포하는 생태계가 문제라고 봄
-
이 글을 보니 예전에 자주 들먹이던 소프트웨어 법칙이 떠오름
충분히 크고 오래 살아남은 애플리케이션은 결국 자신이 돌아가는 소프트웨어 스택 전체, 운영체제까지도 재구현하게 되고, 그걸 형편없이 재구현한다는 법칙임
출처는 잘 모르겠지만 대체로 맞는 경우가 많음- 재치 있는 버전은 Greenspun의 10번째 법칙으로 알려져 있음
“충분히 복잡한 C나 Fortran 프로그램은 임시방편으로, 비공식 명세에 따라, 버그 많고 느리게 Common Lisp의 절반을 구현한다”
더 일반적인 패턴은 Inner-Platform Effect라고 부름
- 재치 있는 버전은 Greenspun의 10번째 법칙으로 알려져 있음
-
제목의 전제를 넓혀 보면, WASM이 그 계보의 진정한 후계자가 되려면 임의의 호스팅 업체 LAMP 스택에서 PHP 앱을 올리고 배포하던 것만큼 쉬워야 함
아직은 PHP 배포 경험만큼 쉽지는 않은 것 같음- WASM은 브라우저에서 실행됨
호스팅에서 뭐가 달라져야 한다고 기대하는지 모르겠음
- WASM은 브라우저에서 실행됨
-
이건 다르게 봄
미래는 로컬 우선이라고 생각함
앱이 서버 도움을 거의 받지 않고 사용자 브라우저 안에서 대부분 실행되는 방식임
Figma, Linear, Superhuman 같은 앱이 이 모델을 매우 성공적으로 쓰고 있고 Stackblitz도 어느 정도 그렇다
Figma처럼 어느 정도 복잡한 앱이 사용자 브라우저 안에서 거의 전부 실행될 수 있다면, 대부분의 앱도 가능하다고 봄
서버 쪽은 주로 사용자가 여러 위치에서 앱을 쓸 때 서로 다른 인스턴스 간 데이터를 동기화하는 역할을 함
Electric-SQL 같은 도구가 만들어지는 중이지만 아직 성숙하지는 않았고, 이런 라이브러리들이 성숙하면 이 영역이 크게 성장할 것임
서버리스는 대체로 Amazon과 Azure 같은 회사가 돈을 벌기 위한 것이고 결국 CGI처럼 될 것임
WASM도 성공할 수 있지만 주로 사용자 브라우저 안에서일 가능성이 큼
Microsoft는 C#/Blazor에 WASM을 쓰고 있지만, 브라우저 안의 dotnet이 JavaScript만큼 빨라질 것 같지는 않아서 올바른 접근은 아니라고 봄- CGI는 사용자와 작은 사이트에 힘을 줌
초당 1조 개 광고 노출로 확장할 수 없어서 아무도 이야기하지 않을 뿐임
서버리스 함수는 누군가 하나 작성할 때마다 Bezos의 요트에 10피트를 더해줌 - Figma를 로컬 우선이라고 부르기는 애매함
오프라인이거나 와이파이가 불안정한 곳에 있으면 디자인을 로드할 수 없고, 최근에 바뀐 게 아니라면 편집 후 와이파이가 끊긴 상태에서 브라우저를 종료하면 저장되지 않음 - 그러니까 미래는 웹 시대 이전에 앱을 실행하던 방식으로 돌아가는 거라는 얘기네
- 클라이언트 측 애플리케이션 발전은 지지하지만, 반드시 브라우저나 샌드박스 안에서 실행되거나 앱스토어를 통해 구매되어야 한다고 보지는 않음
그리고 전혀 새로운 생각도 아님 - 브라우저 안의 dotnet이 JavaScript만큼 빠르지 않을 수는 있지만, 둘 다 충분히 빠를 것임
우리는 Blazor WASM을 개발하고 있고, 성능 면에서 dotnet은 문제가 아님
- CGI는 사용자와 작은 사이트에 힘을 줌
-
기본적으로 JVM과 그 생태계를 다시 만드는 건가?
- 어느 정도는 맞지만, WASM은 아무 곳에나 런타임을 밀어 넣고 싶을 때 더 맞는 다른 제약 조건을 염두에 두고 설계됐음
과거의 교훈을 반영해 X를 다시 만드는 일이 실제로 훌륭한 아이디어일 때도 있음 - 어떤 면에서는 맞지만, WASM은 훨씬 더 많은 언어를 지원함
예를 들어 2010년쯤 브라우저에서 C/C++ 코드를 돌리는 걸 알아보기 시작했을 때 C/C++를 JVM으로 컴파일하는 건 사실상 불가능했음
당시에는 Java Applet이 아직 의미가 있었으니 그게 가능했다면 좋았겠지만, WASM도 아직 없었고 Emscripten은 있었으며, 그것이 asm.js를 거쳐 결국 WASM 탄생으로 이어졌음 - JVM은 훌륭하지만 이 장르의 최종 답이라는 뜻은 아님
2000년대 프로그래밍 언어 수업에서 클래스 로더를 만지고 JVM 어셈블리를 직접 작성해 본 입장에서는 JVM이 이 분야의 최고점인지도 잘 모르겠음
큰 생태계를 가능하게 한 건 맞지만, JVM이 외부 세계와 맞닿는 인터페이스는 정말 투박한 엉망임
20년 넘게 JVM 관련 무언가를 마주칠 때마다 신음이 나왔음
Rust의 패키징과 생태계를 Python이나, 더 끔찍하게는 C++와 비교해 보면, 지난 수십 년의 교훈을 반영한 재발명이 매우 좋은 일이 될 수 있음을 보여줌 - 다만 WASM에는 큰 클래스 로더/링커 문제가 있음
두 개의 wasm 파일을 하나로 합치고 메모리 병합을 제대로 맞추는 일이 아직 매우 어려움
컴포넌트 모델이 고칠 수 있을지도 모르지만 쓸데없이 비대한 요소가 너무 많아서 Safari 채택까지는 오래 걸릴 수 있음 - 맞음, 그리고 .Net CLR 등도 마찬가지임
- 어느 정도는 맞지만, WASM은 아무 곳에나 런타임을 밀어 넣고 싶을 때 더 맞는 다른 제약 조건을 염두에 두고 설계됐음
-
오래전부터 WASM이 클라우드의 Lambda 함수 코드를 대체하는 세계로 갈 거라고 생각해 왔음
WASM은 전통적으로 호스트 플랫폼 위에서 실행되는 것으로 여겨지지만 꼭 그래야 할 이유는 없음
WASM의 샌드박스 성격 때문에 기술적으로는 운영체제 밖이나 ring0에서 실행해 많은 운영체제 오버헤드를 우회할 수도 있음
WASM으로 컴파일하면 사용자 입장에서 여러 배포 문제가 훨씬 단순해지고, 호스팅 환경은 최적화할 여지가 커짐
WASM을 더 빠르게 돌리는 맞춤형 하드웨어까지 가능할 수 있음 -
임의의 신뢰할 수 없는 출처에서 온 임의의 신뢰할 수 없는 코드를 자동 실행해야 하는 것은 나쁘고, 서버 측 CGI와 같은 역할을 채운다고 볼 수도 없음