Design Figma, 수백 명의 디자이너가 픽셀 단위로 동시 편집하는 시스템은 어떻게 설계될까?
"DOM을 버리고 캔버스를 지배하라." 무거운 그래픽 엔진을 웹 브라우저 위에서 60FPS로 돌리기 위한 한계를 다룹니다.
이번에는 글로벌 1위 디자인 협업 툴인 Figma(피그마) 같은 대규모 실시간 그래픽 편집 플랫폼을 설계하는 문제를 다룹니다.
피그마는 디자이너, 기획자, 개발자가 하나의 무한한 캔버스에 모여 UI/UX를 그리고, 수십 개의 마우스 커서가 동시에 움직이며, 픽셀 단위의 벡터데이터를 실시간으로 동기화하는 서비스입니다.
앞서 다루었던 슬랙(텍스트 스트리밍)이나 노션(블록 트리)과는 차원이 다른 엔지니어링 한계에 부딪히게 됩니다. 사용자가 마우스를 드래그하여 사각형의 크기를 조절하는 순간, 브라우저는 1초에 60번(60FPS) 화면을 다시 그려야 하며, 동시에 이 X, Y 좌표의 변화를 수백 명의 다른 접속자들에게 지연 없이 동기화해야 합니다.
AI가 단순한 백엔드 코드를 짜주는 시대에, 시니어 엔지니어의 시스템 디자인 역량은 다음과 같은 질문에서 빛을 발합니다.
“수만 개의 레이어(Layer)와 벡터 이미지를 가진 무거운 디자인 파일을 브라우저 메모리 한계 내에서 어떻게 끊김 없이 렌더링할까?”
“노션처럼 단순한 CRDT만으로는 해결할 수 없는, 도형의 Z-Index(앞뒤 순서)와 그룹화 충돌을 중앙 서버에서 어떻게 조율할까?”
“수십 명의 마우스 커서가 1초에 60번씩 움직이는 압도적인 트래픽(Cursor Movement)을 서버 DB를 터뜨리지 않고 어떻게 중계할까?”
Figma 같은 디자인 툴은 프론트엔드의 극한(WASM/WebGL)과 백엔드의 극한(Stateful Multiplayer Server)이 만나는 시스템 설계의 끝판왕입니다. 이 글을 끝까지 읽으면 다음 질문에 답할 수 있게 됩니다.
웹 브라우저의 한계를 넘기 위해 DOM 대신 WebGL과 WebAssembly(WASM)를 어떻게 설계에 녹여낼 수 있을까?
디자인 파일의 본질인 ‘씬 그래프(Scene Graph)’를 데이터베이스에 어떻게 모델링하고 저장할까?
50명이 동시에 요소를 드래그할 때, 피그마의 중앙 집중형 멀티플레이어 서버는 충돌을 어떻게 해결할까?
초당 수백 번 쏟아지는 ‘실시간 마우스 커서’ 데이터를 메인 DB 트래픽과 완벽히 격리하는 방법은?
기가바이트(GB) 단위로 커진 디자인 파일을 1초 만에 열기 위한 스냅샷(Snapshot) 청크 전략은?
Functional Requirements - 기능적 요구사항
무한 캔버스와 벡터 렌더링
사용자는 브라우저에서 벡터 도형, 이미지, 텍스트를 그리고 줌/팬(Zoom & Pan)을 할 수 있어야 합니다.
씬 그래프 (Scene Graph) 계층
프레임(Frame), 그룹(Group), 레이어(Layer) 등으로 요소들이 부모-자식 트리 관계를 가져야 합니다.
실시간 멀티플레이어 (Real-time Multiplayer)
여러 사용자가 동시에 동일한 파일을 편집할 수 있으며, 다른 사람의 마우스 커서 움직임이 실시간으로 보여야 합니다.
히스토리 및 버전 관리
과거의 특정 시점으로 파일을 되돌리거나(Undo/Redo), 버전 스냅샷을 저장할 수 있어야 합니다.
Non-Functional Requirements - 비기능적 요구사항
Zero-Latency Rendering (60FPS)
마우스를 드래그하는 즉시 로컬 화면에 지연 없이(16ms 이내) 렌더링되어야 합니다. 네이티브 앱 수준의 퍼포먼스가 필수입니다.
Low Latency Sync (< 50ms)
내 마우스 움직임과 편집 내용이 다른 사용자에게 50밀리초 이내에 도달하여 ‘같은 공간에 있는 듯한’ 경험을 주어야 합니다.
High Consistency (강력한 일관성)
디자인 툴의 특성상 1픽셀이라도 어긋나면 안 됩니다. 모든 사용자의 브라우저는 정확히 100% 동일한 좌표와 레이어 순서를 렌더링해야 합니다.
High Durability
디자인 파일은 회사의 핵심 자산이므로 절대 유실되어서는 안 됩니다.
Scope 정리
In Scope
프론트엔드 렌더링 아키텍처(WASM/WebGL)
씬 그래프 데이터 모델링
실시간 동기화(Multiplayer Server)
마우스 커서 브로드캐스팅
파일 저장 및 로딩 최적화
Out of Scope
피그마 커뮤니티 플랫폼
플러그인 생태계 실행 샌드박스
결제 시스템.
가정하는 규모
DAU: 1,000만 명
Concurrent Users (Peak): 200만 명
Active Multiplayer Sessions: 동시 편집 중인 파일 수십만 개
Peak QPS (WebSocket):
문서 편집 이벤트: 수십만 QPS
마우스 커서 이벤트: 수백만 ~ 수천만 QPS (가장 무거운 트래픽)
Core Entities
피그마의 데이터 모델은 일반적인 블로그나 슬랙처럼 텍스트 덩어리를 데이터베이스에 통째로 저장하는 방식이 아닙니다. 피그마 파일의 본질은 화면에 그려지는 수만 개의 그래픽 요소들이 부모-자식 관계로 복잡하게 얽혀 있는 거대한 트리 구조, 즉 씬 그래프(Scene Graph) 라고 할 수 있습니다.
files (파일 메타데이터)
디자인 파일의 껍데기 역할을 합니다. 파일 이름, 워크스페이스 ID, 썸네일 URL 등의 기본 정보를 담고 있습니다.
대규모 분산 환경에서 특정 서버로 트래픽을 몰아주거나 데이터베이스를 쪼갤 때(Sharding), 이
file_id가 가장 중요한 파티션 키(Partition Key)로 활용됩니다.
nodes
피그마 캔버스 위에 존재하는 모든 것은 ‘노드(Node)’입니다. 도화지 역할을 하는 프레임(Frame)도 노드이고, 그 안의 사각형(Rectangle), 텍스트(Text), 다각형(Polygon)도 모두 하나의 노드 레코드로 저장됩니다.
id: 각 요소의 분산 고유 식별자(UUID).file_id: 이 노드가 속한 파일의 ID. 파일을 열 때 해당 파일의 모든 노드를 한 번에 긁어오기 위한 핵심 인덱스입니다.parent_id: 이 요소를 감싸고 있는 부모 노드(예: 특정 프레임이나 그룹)의 ID입니다. 이 필드를 통해 씬 그래프라는 깊은 트리(Tree) 구조가 조립됩니다.type:FRAME,GROUP,RECTANGLE,TEXT등 요소의 형태.properties: X, Y 좌표, 너비(Width), 높이(Height), 채우기 색상(Fill), 선 굵기(Stroke) 등 픽셀 렌더링에 필요한 무거운 메타데이터가 담긴 페이로드(주로 JSONB 형식).z_index: 같은 부모 내에서 어떤 요소가 더 화면 앞쪽에 렌더링되어야 하는지를 결정하는 깊이 순서입니다. 동시 편집 상황에서 가장 충돌이 잦고 서버가 깐깐하게 조율해야 하는 핵심 속성입니다.
snapshots (스냅샷 저장소)
기가바이트(GB) 단위로 무거워진 디자인 파일을 열 때, 과거에 마우스로 움직였던 수백만 번의 변경 기록(Delta Log)을 데이터베이스에서 처음부터 끝까지 다시 조립(Replay)한다면 로딩에만 수 분이 걸릴 것입니다.
이를 방지하기 위해, 시스템은 주기적으로 특정 시점의 전체 씬 그래프 상태를 하나로 압축합니다. 그리고 이를 AWS S3와 같은 오브젝트 스토리지(Blob Storage)에 통째로 박제(Check-pointing)해 둡니다. 클라이언트는 이 무거운 스냅샷 파일의 URL만 받아와 초고속으로 초기 화면을 렌더링합니다.
API Signatures
피그마의 진가는 단순한 데이터의 저장이 아니라, 프론트엔드의 렌더링 최적화와 서버의 멀티플레이어 아키텍처에 있습니다. 프론트엔드 시스템 디자인 강의는 현재 제작중에 있습니다.
텍스트 기반의 협업 툴(슬랙, 노션)이 대부분 REST API에 의존하는 반면, 피그마는 초기 로딩을 제외한 모든 편집 과정이 WebSocket을 통한 ‘실시간 스트리밍(Streaming)’과 ‘상태 동기화(State Sync)’로 이루어집니다.
단순한 JSON 페이로드를 넘어서, 이 데이터를 어떻게 처리해야 60FPS의 렌더링과 충돌 없는 동기화를 달성할 수 있는지 API 파이프라인으로 나누어 알아보겠습니다.
1. File Load APIs (파일 초기 로딩 - 스냅샷 기반 Read Path)
수만 개의 레이어와 기가바이트(GB) 단위의 고해상도 이미지가 포함된 디자인 파일을 열 때, 일반적인 웹 서비스처럼 DB에서 데이터를 긁어와 화면을 그리려 한다면 사용자는 5분 넘게 하얀 화면(White Screen of Death)만 쳐다봐야 할 것입니다.
피그마의 초기 로딩은 API 서버가 무거운 데이터를 직접 다루지 않고, 오브젝트 스토리지(S3)로 부하를 완벽히 오프로딩(Offloading)하는 전략을 취합니다.


