-
로컬-퍼스트 앱은 빠른 반응 속도와 기본적인 프라이버시 보장을 약속하지만 실질적으로 오프라인 지원 구현이 매우 어렵다는 한계가 존재함
- 가장 큰 이유는 동기화의 복잡성 때문이며, 여러 기기에서 동시에 데이터를 변경하면 결과적으로 정확히 동일한 상태로 수렴해야 한다는 문제점이 발생함
-
시간순서 불확실성과 충돌이라는 두 가지 큰 기술적 과제가 있음
- 이 문제를 해결하기 위해 Hybrid Logical Clocks(HLCs) 와 CRDTs와 같은 분산 시스템 설계를 적용하는 방법이 필요함
-
SQLite 기반 확장 기능을 활용함으로써 신뢰성 높고 간단한 동기화 아키텍처를 제공할 수 있으며, 이는 모든 플랫폼에서 활용 가능함
오프라인-퍼스트 앱의 약속과 현실
- 오프라인-퍼스트 앱은 즉각적인 반응, 기본 프라이버시 보장, 불안정한 네트워크 환경에서도 로딩 대기 없이 사용 가능함을 표방함
- 실제로는 대부분의 앱들이 오프라인 지원을 제대로 구현하지 못하며, 대다수는 변화를 로컬에 임시 저장한 후 나중에 네트워크 연결 시 전송하는 방식만 채택함
- 이런 구현은 신뢰성이 떨어지며, 결국 "변경사항이 저장되지 않을 수 있음"과 같은 경고 메시지로 이어짐
동기화의 근본적인 어려움
- 로컬-퍼스트 앱을 만들 때는 필연적으로 분산 시스템을 구축하게 됨
- 여러 기기가 오프라인 환경에서 서로 독립적으로 데이터를 변경할 수 있고, 나중에 다시 연결되었을 때 동일한 상태로 정확히 수렴해야 함
- 이를 위해서는 두 가지 큰 도전 과제가 존재함
-
이벤트의 순서 불확실성
-
동일 데이터에 대한 충돌
1. 이벤트 순서 불확실성
- 여러 기기에서 이벤트가 서로 다른 시점에 발생하며, 순서에 따라 상태가 달라질 수 있음
- 예시: A 기기는 x=3으로 설정, B 기기는 x=5로 설정 → 오프라인에서 각각 변경한 후 동기화 시 서로 다른 결과 발생 가능성
- 기존 중앙 집중형 데이터베이스는 강력한 일관성으로 해결하지만, 이는 글로벌 동기화가 필요해 로컬-퍼스트 시스템에는 맞지 않음
- 최종적으로는 이벤트별로 적절한 순서를 동적이고 분산된 환경에서도 확정해야 함, 중앙 시계 없이 순서를 정하는 방법이 필요함
Hybrid Logical Clocks(HLCs)의 도입
-
Hybrid Logical Clocks(HLCs) 는 개별 기기 간에 이벤트 순서를 실질적으로 합의할 수 있게 해 주는 단순하면서 효과적인 알고리듬임
- HLC는 물리적 시간 정보와 논리적 카운터를 결합하여 사용함
- 예시로:
- A 기기가 10:00:00.100 시각에 이벤트를 기록, HLC는 (10:00:00.100, 0)
- 메시지를 받은 B 기기는 자신의 시계가 느리더라도, HLC를 (10:00:00.100, 1)로 올림
- 이로 인해 두 기기의 물리적 시계 차이와 상관없이 정확한 이벤트 순서 확정 가능
2. 충돌 문제
- 올바른 순서 적용만으로는 충분하지 않고, 서로 다른 기기에서 동일 데이터를 독립적으로 수정할 경우 충돌이 필연적으로 발생함
- 대부분의 시스템은 개발자가 충돌 해결 코드를 수동으로 작성하도록 요구하지만, 이는 오류 발생 위험과 관리 부담을 초래함
CRDTs의 활용
-
Conflict-Free Replicated Data Types(CRDTs) 를 적용하는 것이 가장 좋은 방법임
- CRDTs는 어떤 순서로 동기화해도, 또는 중복 적용해도 각 기기 상태가 최종적으로 항상 동일해짐을 보장함
- 가장 단순한 CRDT 전략은 Last-Write-Wins(LWW) 임
- 각 업데이트에 타임스탬프를 부여
- 동기화 시 더 최신 타임스탬프의 값이 선택됨
SQLite의 장점
- 로컬-퍼스트 앱을 구축할 때는 신뢰성 높고 가벼운 로컬 DB가 필수이며, SQLite가 최적의 선택임
- SQLite 기반 프레임워크 확장으로 동기화 기능을 구현하면 다음과 같은 이점이 있음
- 메시지 적용은 단순: 현재 값 조회 → 신규 타임스탬프가 더 최신이면 덮어쓰기 → 그렇지 않으면 무시
- 이 방식은 동기화 순서와 무관하게 전 기기에서 상태 수렴성 보장
아키텍처의 의의
- 이 구조는 단순하고 신뢰성 높은 동기화를 실현함
- 수 주 동안 오프라인 상태에서도 데이터 유실 없는 신뢰성
- 항상 최종 상태로 수렴하는 결정론적 특성
- 무거운 의존성 없는 경량 SQLite 확장만으로 해결
- iOS, Android, macOS, Windows, Linux, WASM 등 모든 주요 플랫폼 지원
개발자를 위한 제언
- 단순한 요청 큐로 오프라인 모드 지원을 '흉내' 내는 방식을 지양할 필요
-
이벤트얼 컨시스턴시 개념을 받아들이고, HLC 및 CRDT와 같은 입증된 분산시스템 기술을 활용할 필요
- 크고 복잡한 프레임워크 대신 작고 의존성 없는 구조 추구가 바람직함
- 결과적으로 앱은 즉시 실행, 오프라인 사용 가능, 기본 프라이버시 보장 등의 장점을 누릴 수 있음
오픈소스 SQLite-Sync 참고 안내
- 프로덕션에서 즉시 쓸 수 있는, 크로스플랫폼 오프라인-퍼스트 엔진에 관심 있다면, 오픈소스 SQLite-Sync 확장 참고 가능