figma3분 읽기

큐레이션 요약

대규모 실시간 데이터를

원문 읽기(새 탭에서 열림)

Figma의 실시간 데이터 서비스 LiveGraph는 사용자와 쿼리 증가, 데이터베이스 샤딩으로 기존 구조의 한계에 도달했다. Figma는 초기 로컬 캐시와 단일 PostgreSQL의 전역 변경 스트림에 의존하던 아키텍처를 100배 규모까지 확장할 수 있도록 근본적으로 재설계하려 했다. 새 설계의 목표는 성능과 안정성을 유지하면서 데이터베이스 샤드와 읽기·업데이트 부하를 독립적으로 확장하고, 사용자 영향 없이 점진적으로 마이그레이션하는 것이다.

LiveGraph의 역할

  • LiveGraph는 GraphQL과 유사한 쿼리를 구독하는 웹 API를 제공한다.
  • 쿼리 결과를 JSON 트리로 반환하며, 객체와 관계를 정의한 스키마와 특정 그래프 일부를 조회하는 뷰를 사용한다.
  • Figma의 커스텀 React Hook을 통해 데이터가 변경되면 프런트엔드가 자동으로 다시 렌더링된다.
  • 캔버스 공동 편집, 댓글, FigJam 투표 등 여러 협업 기능에서 최신 데이터를 유지하는 기반 역할을 한다.

규모 증가로 드러난 문제

  • 2021년 이후 LiveGraph 세션 수가 3배 증가했다.
  • 최근 1년 동안 뷰 요청 수는 5배 늘어났고, 세션 하나의 처리 비용도 점점 커졌다.
  • 데이터베이스 역시 단일 PostgreSQL 인스턴스에서 여러 수직·수평 샤드 구조로 변화하고 있었다.
  • 따라서 문제는 단순히 각 LiveGraph 서버가 데이터베이스 변경 사항을 모두 수집하는 데 그치지 않고, 클라이언트 세션·읽기 요청·데이터베이스 업데이트가 동시에 증가하는 복합적인 확장성 문제였다.

LiveGraph 100x의 설계 목표

Figma는 현재의 읽기 및 데이터베이스 업데이트 부하를 장기적으로 100배까지 처리하기 위한 “LiveGraph 100x” 계획을 시작했다.

  • 서비스 속도 유지
    • 초기 로드 시간과 실시간 업데이트에 대한 SLO를 유지하거나 개선해야 했다.
  • 데이터베이스 확장 지원
    • 수직 확장뿐 아니라 수평 샤딩도 기본적으로 지원해야 했다.
    • 샤드가 늘어나도 신뢰성과 성능이 저하되지 않아야 했다.
  • 독립적인 확장 수단 확보
    • 클라이언트 읽기량이 증가할 때와 쿼리 업데이트량이 증가할 때 서로 다른 구성 요소를 확장할 수 있어야 했다.
  • 안전한 점진적 마이그레이션
    • 기존 LiveGraph 사용자를 중단시키지 않고 단계적으로 구조를 개선해야 했다.

초기 아키텍처와 변경 스트림

초기 LiveGraph는 단일 PostgreSQL과 하나의 서버를 중심으로 구성됐다.

  • PostgreSQL의 논리적 복제 스트림은 WAL에 기록된 행 단위 변경 사항을 전달한다.
  • 각 변경에는 행의 변경 전·후 이미지와 단조 증가하는 시퀀스 번호가 포함된다.
  • LiveGraph는 이 스트림을 추적해 데이터 변경을 실시간 업데이트로 재사용했다.
  • 모든 LiveGraph 쿼리는 기본 데이터베이스인 primary를 조회했다.
  • 서버 내부에는 인메모리 쿼리 캐시가 있었고, PostgreSQL의 각 행 변경이 발생할 때마다 관련 쿼리 결과를 직접 수정했다.
  • 즉, 캐시는 전체 결과를 다시 계산하기보다 개별 mutation을 결과에 반영하는 방식이었다.

단일 데이터베이스 구조의 한계

초기 구조에서는 데이터베이스가 하나였기 때문에 변경 스트림의 전역 순서를 가정할 수 있었다.

  • 모든 변경 사항이 하나의 PostgreSQL 인스턴스에서 생성됐다.
  • 따라서 LiveGraph는 하나의 전역적으로 정렬된 업데이트 스트림을 처리하면 됐다.
  • 하지만 단일 PostgreSQL 인스턴스가 용량 한계에 도달하면서 데이터베이스를 여러 수직 샤드로 나누게 됐다.
  • 여러 샤드가 동시에 변경 사항을 생성하면서 업데이트의 전역 순서가 더 이상 보장되지 않았다.
  • 기존의 “하나의 전역 순서 스트림”이라는 가정은 샤딩된 데이터베이스 환경에서 유지될 수 없었다.

재설계가 필요해진 이유

  • LiveGraph는 데이터베이스 확장에 맞춰 변경 사항 수집과 캐시 갱신 방식을 바꿔야 했다.
  • 수직·수평 샤딩 환경에서는 여러 변경 스트림을 안정적으로 처리해야 한다.
  • 읽기 요청과 실시간 업데이트가 서로 다른 속도로 증가하므로, 전체 시스템을 한 방식으로만 확장해서는 효율적이지 않다.
  • Figma는 데이터베이스 용량 문제에 신속히 대응하면서도 기존 서비스의 성능과 안정성을 유지할 수 있는 전략적 변경이 필요했다.

실무적으로는 단일 데이터베이스의 전역 순서와 중앙 캐시에 의존하는 실시간 시스템이 초기에는 단순하고 효율적이지만, 샤딩 단계에서는 변경 순서·캐시 일관성·부하 분리 문제를 별도로 설계해야 한다는 점을 보여준다.

큐레이션 요약을 이어서 읽어보세요.