Articlestack.convex.dev·2026년 7월 8일·0

An Object Sync Engine for Local-first Apps

Quick Summary

이 글은 로컬 퍼스트 웹 앱에 적합한 객체 동기화 엔진을 정의하고, 로컬 저장소·서버 저장소·동기화 프로토콜의 역할을 기존 사례와 컨벡스의 방향으로 비교한다.

An Object Sync Engine for Local-first Apps 관련 대표 이미지

🖼️ 인포그래픽

An Object Sync Engine for Local-first Apps 내용을 설명하는 본문 이미지

🖼️ 4컷 인포그래픽

An Object Sync Engine for Local-first Apps 내용을 설명하는 본문 이미지

💡 한 줄 요약

이 글은 로컬 퍼스트 웹 앱에 적합한 객체 동기화 엔진을 정의하고, 로컬 저장소·서버 저장소·동기화 프로토콜의 역할을 기존 사례와 컨벡스의 방향으로 비교한다.

📌 핵심 요약

  • 객체 동기화 엔진은 클라이언트와 중앙 서버 사이에서 작은 앱 메타데이터 객체들의 그래프를 동기화하는 방식이며, UI는 로컬 저장소를 직접 읽고 쓴다.
  • 이 글은 이 엔진의 적합한 범위를 약 100MB의 메모리 중심 데이터, 1Hz 수준의 업데이트, 높은 구조성, 강한 오프라인 지원, 서버 권위와 강한 일관성으로 설명한다.
  • 로컬 저장소는 네트워크를 기다리지 않는 사용자 경험, 오프라인 영속성, 앱 버전 간 데이터 호환, 여러 탭이나 스레드의 동시 접근을 처리해야 한다.
  • 서버 저장소는 권위 있는 데이터 사본을 보관하며, 데이터 불변식 유지, 내구성, 대용량 저장, 서버 측 계산, 알림 전파 같은 이유로 중앙화의 이점을 제공한다.
  • 동기화 프로토콜은 초기 동기화, 증분 동기화, 클라이언트 변이 전송, 낙관적 업데이트의 적용과 롤백을 다루며, 루나디비·레플리캐시·컨벡스는 서로 다른 방식으로 이를 구현한다.

🧩 주요 포인트

  1. 객체 동기화 엔진은 클라이언트와 중앙 서버 사이에서 작은 앱 메타데이터 객체들의 그래프를 동기화하는 방식이며, UI는 로컬 저장소를 직접 읽고 쓴다.
  2. 이 글은 이 엔진의 적합한 범위를 약 100MB의 메모리 중심 데이터, 1Hz 수준의 업데이트, 높은 구조성, 강한 오프라인 지원, 서버 권위와 강한 일관성으로 설명한다.
  3. 로컬 저장소는 네트워크를 기다리지 않는 사용자 경험, 오프라인 영속성, 앱 버전 간 데이터 호환, 여러 탭이나 스레드의 동시 접근을 처리해야 한다.
  4. 서버 저장소는 권위 있는 데이터 사본을 보관하며, 데이터 불변식 유지, 내구성, 대용량 저장, 서버 측 계산, 알림 전파 같은 이유로 중앙화의 이점을 제공한다.
  5. 동기화 프로토콜은 초기 동기화, 증분 동기화, 클라이언트 변이 전송, 낙관적 업데이트의 적용과 롤백을 다루며, 루나디비·레플리캐시·컨벡스는 서로 다른 방식으로 이를 구현한다.

🧠 상세 정리

1. 객체 동기화 엔진이라는 범위 설정

글은 이전 글에서 동기화 엔진을 아홉 가지 차원으로 분류한 배경 위에, 로컬 퍼스트 웹 애플리케이션에 특히 잘 맞는 영역으로 객체 동기화 엔진을 제시한다. 여기서 객체는 작업의 제목, 설명, 상태, 프로젝트 포인터, 담당자 포인터처럼 작지만 내부 구조와 관계가 많은 애플리케이션 메타데이터를 뜻한다. 리니어, 피그마, 아사나가 각자 동기화 엔진, 라이브그래프, 루나디비를 개발했고, 레플리캐시는 여러 종류의 앱에 적용 가능한 일반 엔진 가능성을 보인 사례로 등장한다. 컨벡스는 자사 플랫폼에서 로컬 퍼스트 앱을 더 쉽게 만들기 위해 같은 범주의 객체 동기화 엔진을 만들고 있다고 설명한다.

2. 로컬 객체 그래프와 서버 권위 모델

객체 동기화 엔진은 클라이언트와 중앙 서버 사이에서 객체 그래프를 동기화한다. 애플리케이션은 이 객체 그래프를 로컬 저장소에 보관하고, 사용자가 화면에서 상호작용할 때 UI가 로컬 저장소를 직접 읽고 쓴다. 글에서 다루는 앱들은 모두 중앙 서버에 권위 있는 객체 그래프를 보관하며, 동기화 엔진이 로컬 저장소와 서버 저장소를 맞춘다. 두 저장소의 스키마는 자주 달라질 수 있고, 개발자는 하나의 논리적 변경을 서버의 권위 있는 변경과 로컬 저장소의 낙관적 업데이트로 각각 구현해야 한다. 서버가 변경을 적용한 뒤에는 로컬 스키마와 같은 형식으로 클라이언트에 다시 동기화한다.

3. 아홉 차원으로 본 설계 지점

글은 객체 동기화 엔진의 적정 지점을 여러 차원으로 정리한다. 데이터 크기는 풍부한 웹 앱이 메모리 속도로 읽고 쓰기에 적당한 약 100MB로 보고, 그보다 한 자릿수 이상 커지면 보조 저장소로 넘기는 문제가 생긴다고 설명한다. 업데이트 속도는 풍부한 객체 그래프가 보통 60Hz 같은 상호작용 주기를 요구하지 않기 때문에 1Hz 정도를 기준으로 삼고, 피그마가 느린 업데이트와 더 빠른 문서 영역을 나누어 다룬다는 예를 든다. 구조성, 오프라인 지원, 유연성, 일관성은 높게 요구되며, 협업 앱의 입력 지연은 경쟁적 시스템이 아니므로 500ms 정도도 충분할 수 있다고 본다. 또한 많은 클라이언트가 동시에 붙을 수 있어야 하고, 직렬화 가능한 프로그래밍 모델과 좋은 사용자·개발자 경험을 위해 서버 권위의 중앙화가 적합하다고 주장한다.

4. 로컬 저장소가 맡는 사용자 경험

로컬 퍼스트의 핵심 아이디어 중 하나는 사용자가 데이터를 읽거나 쓸 때 네트워크를 기다리느라 스피너를 보지 않아야 한다는 점이다. 글은 이를 다음 프레임에 데이터를 돌려주는 경험으로 표현하며, 서버에 물어볼 수 없다면 앱은 반드시 어떤 로컬 데이터 저장소에 물어봐야 한다고 설명한다. 오프라인 지원은 사용자가 앱을 닫았다가 다시 열어도 데이터가 남아 있는 영속성을 요구하며, 웹에서는 인덱스디비가 흔한 선택이고 OPFS API를 활용하려는 새로운 작업도 언급된다. 영속 데이터는 코드 버전이 달라진 뒤에도 읽힐 수 있으므로 버전 관리가 필요하다. 또 여러 스레드나 같은 출처의 여러 탭이 같은 인덱스디비나 OPFS 인스턴스에 접근할 수 있기 때문에 로컬 저장소는 동시성도 처리해야 한다.

5. 로컬 저장소의 기존 구현과 컨벡스 방향

기존 사례로 루나디비와 레플리캐시는 모두 로컬 저장소에 인덱스디비를 사용한다. 레플리캐시는 같은 출처의 여러 탭 사이에서 업데이트를 조율하기 위해 브로드캐스트채널을 사용하고, 서로 다른 앱 버전에서 열린 탭을 처리하기 위해 가벼운 다중 버전 관리 방식을 둔다. 컨벡스도 첫 출시에서는 인덱스디비를 사용할 계획이라고 밝힌다. 다만 장기적으로는 웹뿐 아니라 모바일과 데스크톱까지 같은 동기화 엔진을 확장하려 하기 때문에, 미래에는 어떤 형태의 SQLite로 전환할 가능성이 있다고 설명한다. 이 부분은 로컬 저장소가 단순 캐시가 아니라 오프라인, 버전 차이, 여러 실행 환경을 모두 고려하는 핵심 구성요소임을 보여준다.

6. 서버 저장소가 필요한 이유

중앙화된 동기화 앱은 권위 있는 데이터 사본을 서버 저장소에 둔다. 글은 그 이유로 먼저 사용성을 들며, 하나의 서버나 거의 같은 버전의 서버 집합에서 데이터 불변식을 유지하는 편이 서로 다른 버전의 수많은 클라이언트를 상대하는 것보다 단순하다고 설명한다. 또한 데이터센터의 저장 시스템은 사용자가 로컬 기기를 잃어버려도 데이터를 안전하게 보관할 수 있는 내구성을 제공한다. 저장 용량 면에서도 대규모 배포의 작업 데이터가 클라이언트 로컬 용량을 넘어설 수 있기 때문에 서버 쪽 저장소가 중요하다. 서버는 소비자 기기에서 실행하기 부담스러운 계산을 맡을 수 있고, 낮은 지연이 필요한 앱에서는 마지막 구간을 제외한 네트워크를 중앙에서 관리하는 이점도 있다. 대부분의 동기화 애플리케이션은 저장뿐 아니라 관심 있는 클라이언트에 업데이트를 밀어주는 알림 기능도 구현한다.

7. 서버 저장소의 선행 사례와 반응형 데이터베이스

루나디비는 커스텀 애플리케이션 서버와 마이에스큐엘에 데이터를 저장하는 구조를 사용한다. 별도의 무효화 서비스가 복제 로그를 따라가며 관련 동기화 서버로 무효화를 스트리밍하고, 동기화 서버가 다시 클라이언트에 알린다. 리니어도 비슷한 구조로, 클라이언트는 그래프큐엘 서버에 질의하고 별도의 동기화 서버가 포스트그레스 복제 로그를 따라가며 로컬 저장소를 최신 상태로 유지한다. 레플리캐시는 백엔드에 구애받지 않는 방식이라 사용자가 서버 저장소를 가져오며, 예시 앱에서는 버셀의 백엔드 API, 수파베이스 저장소, 수파베이스 리얼타임을 사용한다. 컨벡스는 포스트그레스와 달리 처음부터 반응형 데이터베이스로 설계되어, 질의를 실행하고 그 변경 사항을 효율적으로 구독하는 기능을 일급으로 제공하며 읽기와 쓰기는 직렬화 가능한 트랜잭션으로 실행되는 자바스크립트 함수로 지정된다.

8. 동기화 프로토콜과 프로그래밍 가능성

동기화 프로토콜은 로컬 저장소와 서버 저장소를 연결하는 접착제 역할을 하며, 초기 페이지 로드에서 데이터 집합을 효율적으로 내려받는 초기 동기화, 서버 변경을 따라잡는 증분 동기화, 오랫동안 오프라인이었던 클라이언트의 재동기화, 로컬 변경의 서버 전파를 다룬다. 루나디비는 미티어의 동기화 프로토콜인 DDP를 바탕으로 하며, 클라이언트가 질의와 연결된 구독을 등록하면 서버가 구독 사이의 객체 업데이트를 중복 제거하고 웹소켓으로 푸시한다. 레플리캐시는 /pull, /push, /poke 세 메서드로 프로토콜을 구성하며, /pull은 이전 요청 이후의 변경만 내려받을 수 있고 서버에 적용된 각 클라이언트 변이 정보도 알려준다. 컨벡스의 웹소켓 프로토콜은 질의 집합을 동기화하고 클라이언트에서 서버로 변이를 보내는 일을 조율한다. 글은 컨벡스가 더 세밀한 증분 업데이트, 클라이언트의 새 문서 아이디 할당, 구독 재개, 질의 체이닝을 오프라인 동기화 개선 방향으로 준비하고 있다고 설명한다. 마지막으로 개발자는 로컬 스키마를 통해 동기화되는 데이터의 모양과 읽기·쓰기 인터페이스를 정하며, 모든 사례에서 로컬 스키마가 서버 스키마와 달라질 수 있다는 점이 강조된다.

🧾 핵심 주장 / 시사점

  • 이 글에서 로컬 퍼스트는 중앙 서버를 배제하는 모델이 아니라, 서버 권위와 강한 일관성을 유지하면서도 사용자 인터페이스는 로컬 저장소를 통해 즉시 반응하게 만드는 실용적 설계로 제시된다.
  • 객체 동기화 엔진의 어려움은 단순히 데이터를 복사하는 데 있지 않고, 로컬 스키마와 서버 스키마의 차이, 낙관적 업데이트, 버전 관리, 여러 탭의 동시성, 오프라인 이후 재개를 함께 다루는 데 있다.
  • 컨벡스가 강조하는 차별점은 반응형 데이터베이스와 직렬화 가능한 자바스크립트 트랜잭션을 바탕으로, 질의 구독과 변이 전송을 동기화 엔진의 기본 구성으로 통합하려는 방향에 있다.

✅ 액션 아이템

  • 로컬 퍼스트 적용 대상 앱의 동기화 범위를 100MB 메모리 중심, 초당 1Hz 업데이트, 높은 구조성으로 제한한다.
  • 로컬 저장소에서 UI를 직접 읽기·쓰기하는 전제로 오프라인 영속성, 버전 간 호환, 다중 탭 동시접근 처리 절차를 설계한다.
  • 동기화 프로토콜의 초기/증분 동기화, 변이 전송, 낙관적 갱신·롤백 경로를 루나디비·레플리캐시·컨벡스 구현 차이와 함께 점검한다.

❓ 열린 질문

  • 초기 동기화·증분 동기화·변이 전송·롤백 단계에서 루나디비·레플리캐시·컨벡스의 핵심 차이는 무엇이며 선택 기준은 어떻게 두어야 하는가?
  • 100MB 메모리 중심 데이터와 1Hz 수준 갱신이라는 제약 하에서 서버 권위와 강한 일관성을 유지할 때 예상되는 동기화 지연과 비용은 어떤 패턴으로 나타나는가?
  • 로컬 저장소가 오프라인 영속성과 다중 탭 접근을 모두 처리할 때 앱 버전 간 호환 충돌은 어떤 규칙으로 판단하고 처리해야 하는가?

관련 문서

공통 태그와 주제 흐름을 기준으로 같이 보면 좋은 문서를 이어서 제안합니다.