10,000개 작업을 60fps로 렌더링하는 기술
"간트 차트를 웹에서 실시간으로? 성능이 나올까요?"
2년 전 받은 질문입니다. 답은 "YES, 하지만..."
오늘은 10,000개 작업을 60fps로 렌더링하는 간트 차트를 어떻게 구현했는지 공유합니다.
Canvas, SVG, DOM 중에 뭘로 그릴까 고민했습니다.
Canvas는 빠르지만 상호작용이 어렵고 접근성이 거의 없습니다. DOM은 네이티브 이벤트를 지원하지만 1000개만 넘어도 2초가 걸립니다. SVG는 그 중간입니다. 200ms 정도로 빠르면서도 네이티브 이벤트를 지원합니다.
간트 차트에는 SVG가 최적입니다.
하지만 SVG도 그냥 쓰면 느립니다. 최적화가 핵심이죠.
Object Pooling으로 DOM 조작을 최소화합니다. 작업 바를 재사용하여 생성과 삭제 비용을 줄입니다. CSS Transform을 활용하여 GPU 가속을 받습니다. willChange 속성을 설정하여 브라우저에 최적화 힌트를 제공합니다.
10,000개 작업을 모두 렌더링하면 메모리가 20MB를 넘어갑니다. 해결책은 화면에 보이는 것만 렌더링하는 겁니다.
스크롤 위치와 뷰포트 높이를 계산하여 보이는 범위를 결정합니다. 버퍼를 추가하여 부드러운 스크롤을 보장합니다. 10,000개 중 실제로는 40개만 렌더링되므로 메모리 사용량이 95% 줄어듭니다.
여러 명이 동시에 같은 작업을 수정하면 어떻게 될까요? CRDT(Conflict-free Replicated Data Type)가 답입니다.
Yjs 라이브러리를 사용하여 충돌 없는 실시간 동기화를 구현합니다. WebSocket을 통해 변경사항을 전송하고, 자동으로 충돌을 해결합니다. A가 시작일을 바꾸고 B가 종료일을 바꿔도 문제없이 병합됩니다.
10,000개 작업 프로젝트 기준으로 초기 렌더링은 1.2초, 스크롤 FPS는 55-60fps, 실시간 업데이트 지연은 50ms, 메모리 사용은 50MB입니다.
최적화 전에는 1000개만 해도 10초가 걸렸습니다. 지금은 50,000개까지 테스트해봤습니다.
프로파일링이 답입니다. Chrome DevTools Performance 탭을 열고 측정하세요. 병목이 어디인지 정확히 알 수 있습니다.
점진적 개선이 중요합니다. 처음부터 완벽할 필요 없습니다. 1단계는 기본 기능 구현(느려도 OK), 2단계는 Virtual Scrolling 적용, 3단계는 WebWorker로 무거운 계산 분리, 4단계는 캐싱 전략 도입, 5단계는 WebAssembly로 핵심 알고리즘 재작성입니다.
사용자 경험을 우선시합니다. 느려도 반응은 즉시 해야 합니다. 사용자 액션에 즉시 피드백을 주고, 무거운 작업은 비동기로 처리합니다.
아무리 기술적으로 완벽해도, 사용자가 안 쓰면 의미가 없습니다.
우리가 집중한 것은 빠른 반응(클릭하면 즉시 움직여야), 부드러운 스크롤(버벅이면 안 써요), 실시간 동기화(협업이 핵심이니까), 직관적 인터페이스(매뉴얼 없이도 OK)입니다.
가장 보람 있었던 순간은 사용자가 "우와, 이거 진짜 빠르네요!"라고 했을 때입니다.
여러분도 웹 기반 간트 차트를 만들 계획이신가요? 이 글이 도움이 되길 바랍니다.
고성능 실시간 간트 차트를 체험해보세요. Plexo