8P by GN⁺ 6일전 | ★ favorite | 댓글 2개
  • 거실 기기용 UI를 Rust와 WebAssembly 기반으로 전면 재구성한 사례
  • 다양한 성능 수준의 기기에서도 고성능과 낮은 입력 지연을 실현하기 위한 구조를 설계
  • React 기반에서 벗어나 Rust 전용 UI SDK를 자체 개발, 높은 생산성 확보
  • Entity-Component-System (ECS) 기반의 아키텍처를 통해 코드 복잡도와 성능 관리
  • WebAssembly와 Rust의 사용으로 인한 장단점 및 문제점에 대한 솔직한 분석

Prime Video UI를 Rust와 WebAssembly로 재구성한 이유

  • Amazon은 다양한 거실 기기(콘솔, 셋톱박스, 스트리밍 스틱, TV 등) 에서 동일한 Prime Video 앱을 실행해야 하는 과제를 가짐
  • 다양한 성능을 가진 디바이스에서 일관된 사용자 경험을 제공하려면 고성능의 UI 엔진이 필수였음
  • 기존에는 React(TypeScript), JavaScript, C++, WebAssembly, Rust의 혼합 기술 스택을 사용
  • JavaScript의 느린 실행 속도와 업데이트 어려움으로 인해 전면 Rust로 이전 결정
  • WebAssembly를 활용하면 앱 업데이트가 쉬워지고, Rust는 성능 최적화에 유리함

거실 기기의 주요 개발 도전과제

  • PS5 같은 고성능 장치부터 저전력 USB 스틱까지 다양한 성능 스펙 대응 필요
  • 각 기기마다 별도 팀을 두지 않고 단일 코드 베이스로 개발해야 함
  • 대부분의 기기에서는 앱스토어 없이 펌웨어 업데이트만 가능하므로 네이티브 코드 업데이트가 어려움
  • UI를 자주 업데이트하려면 JavaScript 및 WebAssembly 기반 코드 사용이 유리함
  • 고성능 요구와 빠른 업데이트 주기의 균형점으로 Rust + WebAssembly 조합 선택

기존 아키텍처와 새로운 Rust 기반 UI 아키텍처 비교

  • 기존 아키텍처는 다음과 같은 구조:
    • React로 UI 로직 작성, Rust(WebAssembly)는 낮은 수준의 UI 엔진 처리
    • React → 메시지 버스 → WebAssembly UI 엔진 → C++ 렌더링 백엔드
  • 입력 지연 문제 해결을 위해 모든 비즈니스 로직을 Rust UI SDK로 마이그레이션
  • 새로운 아키텍처:
    • UI SDK부터 렌더링까지 전부 Rust로 구성
    • 메시지 버스 제거, 모든 처리 과정을 WebAssembly 내부에서 실행
    • 코드가 WebAssembly로 컴파일되어 TV로 전송되며, 기존보다 업데이트 속도 및 반응성 향상

새로운 Rust UI SDK의 주요 구성 요소

  • React와 유사한 컴포저블(Composable) 개념 도입 → 재사용 가능한 UI 구성 단위
  • SignalEffect 기반의 반응형 UI 시스템
    • Signal: 값이 변경되면 관련된 Effect를 트리거함
    • Memo: 이전 값과 달라졌을 때만 반응
  • UI 계층 구조는 compose! 매크로를 통해 정의
  • UI 요소는 Widget(기본 제공 컴포넌트)과 Composables(사용자 정의 구조)로 구성
  • Entity-Component-System(ECS) 아키텍처 사용:
    • Entity: ID
    • Component: 속성 데이터 (ex. Layout, RenderInfo, Text)
    • System: 특정 Component 조합에 대해 로직을 수행하는 함수

ECS 시스템 구조와 동작 방식

  • 각 시스템은 특정 컴포넌트 조합을 필요로 하며, 이를 기반으로 UI 업데이트 처리
  • 예시:
    • Resource Management System: 이미지 컴포넌트 → GPU 업로드 → RenderInfo 업데이트
    • Layout System: 다양한 레이아웃 관련 컴포넌트 계산
    • Rendering System: RenderInfo 기반으로 실제 화면 출력
  • 이 구조를 통해 다양한 페이지를 React에서 Rust로 점진적으로 마이그레이션 가능
  • JavaScript 기반 페이지와 Rust 기반 페이지의 공존 및 전환이 원활

좋은 결과와 이점

  • JavaScript/React 개발자도 Rust UI SDK로 생산성 손실 없이 전환 성공
  • UI SDK의 친숙한 구조 덕분에 러스트 초심자도 빠르게 적응 가능
  • 레이아웃 애니메이션, 빠른 화면 전환 등 이전엔 불가능했던 기능 구현 가능
  • 내부 개발 도구(리소스 매니저, 레이아웃 인스펙터 등)도 Rust 기반으로 신속하게 제작 가능
  • 250ms였던 입력 지연을 33ms까지 대폭 감소 (저사양 기기 기준)

어려웠던 점과 기술적 한계

  • WebAssembly System Interface(WASI) 는 아직 발전 중인 생태계로, Rust 업데이트 시 기존 코드가 깨질 가능성 존재
  • WebAssembly에서는 panic 발생 시 앱 전체 종료 → 안정성 확보에 어려움
    • JavaScript와 달리 예외 처리 미흡 → Result 타입 적극 활용 필요
    • 외부 라이브러리 의존 시 panic-free 구현 유도 필요
  • 브라우저 환경에서는 WebAssembly 및 특정 렌더링 API가 미지원되어 웹 클라이언트에는 미적용

Bytecode Alliance와 생태계 기여

  • Amazon은 Bytecode Alliance의 일원으로 WASI 표준화와 관련 기능 개선에 적극 참여
  • 사용 중인 WebAssembly Micro Runtime은 C 기반이며, Rust 기반인 Wasmtime도 병행 검토
  • WebAssembly 생태계 발전을 위해 직접 기술 피드백 및 개발 참여 중

기타 Q&A

  • 웹 브라우저에서도 가능한가? → 일부 WebKit 브라우저는 WASM 미지원, 성능 저하, 구현 복잡성으로 아직은 고려 중
  • WebGL로 구현은 가능하지만 현재로선 투자 대비 효과가 낮아 보류

요약

  • Prime Video의 Rust+WebAssembly 기반 UI는 고성능, 낮은 입력 지연, 빠른 업데이트라는 3박자를 만족
  • 자체 UI SDK와 ECS 아키텍처는 복잡한 UI 동작을 효율적으로 관리
  • Rust 도입이 쉽지 않지만, 체계적인 설계와 개발 문화로 생산성과 안정성을 동시에 달성
  • WebAssembly 생태계는 아직 발전 중이지만, 실서비스에서 충분히 실현 가능
  • 성공적인 도입은 철저한 프로토타이핑과 점진적 이행 전략에 기반함

상태관리 라이브러리를 기본으로끼는 프론트엔드에 비해 게임이야말로 모든 상태가 모든 상태를 건들이기에 그냥 상남자? 식으로 그냥 하는거라 생각 하고 있긴 한데, 반대로 응용앱에서 ECS를 쓴다는것은 패턴화된 상태관리를 각 개발자 혹은 자체 라이브러리를 사용하는것과 비슷할텐데, 이런부분은 어떻게 했는지 궁금하네요

게임 엔진에서나 보던 ECS를 UI에 적용이라니 이건 좀 신박한 발상이군요. 오늘도 이렇게 하나 배워갑니다.