브라우저가 곧 데이터베이스…로컬 퍼스트의 성숙
컨텐츠 정보
- 조회 537
본문
한때 우리는 단순하고 프로그래밍 기능이 없는 콘솔을 갖춘 메인프레임을 사용했다. 모든 컴퓨팅 파워는 중앙에 집중됐다. 이후 빌 게이츠와 스티브 잡스가 책상마다 개인용 컴퓨터를 보급하면서 컴퓨팅 파워는 분산됐다. 인터넷이 등장하자 브라우저는 세계에서 가장 널리 쓰이는 애플리케이션으로 자리 잡았고, 무게 중심은 다시 서버로 이동했다. 클라우드가 주도권을 쥐었다. 이제 그 진자가 다시 반대 방향으로 움직이고 있다.
여기서는 로컬 퍼스트(local-first) 운동을 조망한다. 웹 브라우저 안에 풍부한 기능을 갖춘 데이터 저장 옵션을 직접 내장하는 새로운 기술 흐름을 살펴본다.
PG라이트 : 브라우저 안의 데이터베이스
현대의 브라우저는 수년간의 집중적인 개발과 실제 환경에서의 검증을 거쳐 진화한 강력한 소프트웨어다. 오늘날 브라우저는 대체로 성능이 뛰어난 기기에서 실행된다. 그럼에도 데이터를 얻으려 할 때마다 서버에 요청을 보내야 한다. 브라우저의 상태 정보는 화면이 새로고침될 때마다 사라지는 일시적 그림자에 가깝다. 로딩 스피너, UI 워터폴, 클릭한 뒤 기다려야 하는 경험은 모두 영속적인 상태를 백엔드에 의존한 결과다.
하지만 다른 접근이 떠오르고 있다. 관계형 데이터베이스 일부를 브라우저에 직접 내장하고, 동기화 엔진이 전체 데이터를 일관되게 유지하도록 하는 방식이다. 브라우저는 서버와 백그라운드에서 동기화되는 로컬 데이터 저장소와 상호작용한다. 그 결과 프런트엔드에서는 즉각적인 반응성을 확보하면서도 백엔드와의 대칭성을 유지할 수 있다. 차세대 브라우저는 단순한 임시 캐시가 아니라 더 견고한 기록 시스템을 갖춘다.
브라우저를 한층 강력한 데이터 저장소로 만드는 여러 기술도 등장했다. 인덱스드DB(IndexedDB)와 웹어셈블리(WebAssembly)가 기반을 마련했고, 브라우저 내 노SQL(NoSQL) 데이터 저장소인 파우치DB(PouchDB) 같은 도구가 뒤를 이었다. 그리고 최근 가장 주목받는 기술로 PG라이트(PGLite) SQL 데이터베이스가 부상했다.
물론 모든 선택에는 대가가 따른다. 데이터베이스를 브라우저로 옮기면 아키텍처 전반에 변화가 생긴다. 특히 웹 개발의 두 축으로 여겨져 온 JSON과 REST에서 점차 거리를 두게 된다는 점이 가장 큰 변화로 꼽힌다.
동형성의 미래
최근 필자는 윈터TC(WinterTC)가 서버와 클라이언트를 동일한 환경으로 맞추는 동형(isomorphic) 자바스크립트의 비전에 한 걸음 더 다가가고 있다고 소개한 바 있다. 서버와 클라이언트가 사실상 같은 런타임에서 동작하는 구조다. 다음 단계는 데이터 저장소에서도 이런 동질성을 구현하는 일이다. 이는 최근 웹어셈블리(WASM)가 성숙 단계에 접어들면서 가능해졌다. 브라우저 안에서 완전한 기능을 갖춘 포스트그레SQL(PostgreSQL) 인스턴스를 실행할 수 있게 된 것이다. 이 WASM 기반 데이터베이스가 바로 PG라이트다.
SQ라이트(SQLite)로도 브라우저에서 엔터프라이즈급 데이터베이스에 근접할 수 있지만, PG라이트는 데이터센터에서 운영하는 것과 동일한 데이터베이스를 그대로 사용한다는 점이 다르다. 데이터베이스 방언에서 오는 마찰을 없앤다. 현대 프로그래밍 기술의 성과로 꼽히는 WASM 런타임이 실제 포스트그레스 코드베이스를 경량 빌드 형태로 실행하도록 뒷받침한다.
이 같은 변화는 우리가 씩 클라이언트(thick client)에 그 어느 때보다 가까워졌음을 보여준다. 물론 세부적으로 따져야 할 요소가 적지 않고, 앞으로 여러 시행착오도 겪게 될 것이다.
형상 기반 동기화
API와 구현이 동일하더라도 전체 데이터베이스를 통째로 잘라 브라우저에 둘 수는 없다. 규모가 너무 크고 보안상으로도 적절하지 않다. 특정 세션에서 해당 사용자가 필요로 하는 데이터만 가져오면 된다.
이때 영향력을 발휘한 개념이 ‘형상 기반(shape-based)’ 동기화다. 엘라스틱SQL(ElectricSQL)이 대중화한 방식으로, PG라이트 역시 이 프로젝트가 주도한다. 형상은 일종의 뷰(view)와 비슷하다. 하나 이상의 쿼리를 정의해 관련 데이터의 일부를 클라이언트 측 데이터베이스에 채워 넣는다. 전체 데이터에 대한 최종 권위는 서버가 가진다. 클라이언트는 서버 안에서 자신이 구독한 특정 형상에만 접근한다. 예를 들어 SELECT * FROM issues WHERE assigned_to = 'me'와 같은 쿼리다.
동기화는 내부적으로 포스트그레스의 네이티브 논리적 복제(logical replication) 프로토콜에 기반한다. 동기화 엔진은 미들웨어 소비자 역할을 맡는다. 서버에서 발생하는 모든 변경 사항이 기록되는 데이터베이스의 WAL(write-ahead log), 즉 실시간 변경 스트림을 구독한다. 클라이언트가 구독한 형상과 일치하는 변경이 발생하면, 해당 업데이트만 백그라운드 웹소켓을 통해 브라우저의 PG라이트 인스턴스로 전송한다. 이 과정은 양방향으로 이뤄진다. 로컬에서 발생한 쓰기 작업은 즉시 UI에 반영한 뒤 큐에 적재해 중앙 데이터베이스로 다시 전송한다. 충돌 해결 로직은 엔진이 처리한다.
과거 PWA(progressive web apps) 초기에는 사용자가 다시 온라인 상태로 돌아왔을 때 실패한 요청을 재실행하도록 명령형 코드를 직접 작성해야 했다. 동작은 했지만 구조가 취약했고, 개발 경험도 만족스럽지 못했다. 최신 동기화 엔진은 이런 작업을 내부에서 처리해 더 세련된 해법을 제시한다.
여기서 이런 의문이 들 수 있다. “브라우저는 휘발성 환경 아닌가? 사용자가 캐시를 지우면 어떻게 되는가?”
동기화 엔진은 이 자연스러운 의문에 대한 해법도 마련했다. 이해를 돕기 위해 깃 아키텍처를 떠올려보자.
- 원격 데이터베이스(깃허브)는 진실의 원천이다.
- 로컬 데이터베이스(사용자의 노트북)는 작업 데이터를 담는다.
사용자가 브라우저 캐시를 삭제해도 데이터 자체를 잃는 것은 아니다. 로컬 저장소만 지운 셈이다. 다시 로그인하면 동기화 엔진이 사실상 git clone을 수행해 사용자의 ‘데이터 형상’을 다시 내려받는다.
충돌 없는 복제 데이터 타입
두명의 사용자가 오프라인 상태에서 동일한 데이터를 동시에 수정하면 어떻게 될까? 일반적인 데이터베이스에서는 마지막에 이뤄진 쓰기 작업이 앞선 변경을 덮어쓴다. 여러 클라이언트가 각자의 형상을 기반으로 작업하고, 그 결과를 중앙 데이터 저장소로 계속 동기화하는 환경에서는 훨씬 정교한 동기화 로직이 필요하다.
이때 등장하는 개념이 CRDT(Conflict-free Replicated Data Types)다.
CRDT라는 이름만 들으면 난해한 수학적 구조처럼 보이지만, 실제로는 동기화 문제를 해결하기 위한 실용적인 데이터 구조다. Map이나 List 같은 구조를 수학적으로 병합할 수 있도록 설계했다. 사람이 개입해야 하는 깃의 머지 충돌과, 여러 사용자의 입력을 자동으로 합치는 구글 독스의 차이라고 보면 이해가 쉽다. CRDT 로직을 적용하면 사용자가 오프라인에서 수정한 내용도 사라지지 않는다. 연결이 복구되면 변경 사항을 자연스럽게 결합한다.
여기까지 읽고 이런 생각이 들 수 있다. 아키텍처가 지나치게 복잡해지는 것 아닌가? 이제 데이터베이스가 두 개이고, 동기화 엔진이 있으며, ‘형상’은 서버에 있어야 할 SELECT 문을 또 한 번 정의하는 구조처럼 보인다.
우리는 전통적으로 어려운 문제로 꼽히는 분산 컴퓨팅을 데이터 저장소 계층에서 나눠 처리하고 있다. 데이터 로딩의 불편함을 줄이기 위한 선택이지만, 그 대가로 웹 개발의 익숙한 패턴, 즉 JSON API와 REST에서 벗어나고 있다.
그렇다면 이런 복잡성을 감수하면서까지 얻으려는 가치는 무엇일까?
JSON API를 넘어
이 새로운 접근 방식은 웹 개발자들이 20년 넘게 추구해 온 목표, 즉 데스크톱급 사용자 경험을 가능하게 한다.
로컬 데이터와 직접 상호작용하면 네트워크 호출에 의존할 때는 도달하기 어려운 수준의 UI 반응성을 확보할 수 있다. 완전한 포스트그레SQL 인스턴스를 브라우저로 가져오는 방식은 단순한 로컬 캐시 같은 임시방편을 피하는 근본적 해법이다. 동시에 개발자 경험 측면에서도 또 다른 이점을 기대할 수 있다.
백엔드 API를 제거하면 웹 개발자가 오랫동안 감내해 온 결합 계층 하나가 사라진다. 클라이언트 데이터를 전송용 포맷으로 변환하고, 다시 데이터 저장소 포맷으로 바꾼 뒤 또 한 번 되돌리는 과정을 수작업으로 처리하지 않아도 된다. HTMX 같은 프레임워크도 다른 방식으로 이 이상을 추구한다.
로컬 퍼스트 데이터 모델에서는 JSON을 직렬화하고 역직렬화하는 과정을 거칠 필요가 없다. 필요한 SQL 문을 작성하면, 동기화 엔진이 정의한 규칙에 따라 전송 과정을 자동으로 처리한다. 더 이상 GET /todos 같은 엔드포인트를 작성하지 않는다. 대신 컴포넌트 안에 SELECT * FROM todos와 같은 SQL 쿼리를 직접 쓴다.
인덱스드DB와 OPFS
PG라이트는 분명 흥미로운 기술이지만, 로컬 퍼스트 데이터의 전부는 아니다. 더 큰 기술 생태계의 일부에 가깝다. 개발자들은 오래전부터 데이터를 저장할 방법을 찾아왔다. 로컬스토리지(localStorage), 쿠키, 인덱스드DB가 대표적이다.
인덱스드DB는 브라우저에 데이터베이스를 제공하려는 본격적인 시도였다. 실제로 PG라이트 인스턴스를 뒷받침하는 저장소로도 활용할 수 있다. 하지만 악명 높은 복잡한 API와 성능 제약에 발목을 잡혀 있다. 데이터베이스 엔진이라기보다는 파일 시스템 버킷에 가깝다. 복잡한 쿼리, 조인, 제약 조건을 지원하지 않는다. 조금이라도 의미 있는 작업을 하려면 자바스크립트로 데이터베이스 로직을 직접 작성해 데이터를 메모리로 불러와 필터링해야 한다. 성능이 떨어질 수밖에 없다. 실제 환경에 적용하기에는 구조가 지나치게 복잡하다.
인덱스드DB는 필요한 중간 단계였지만, 최종 목적지는 아니다. 현대적 전환의 기반은 웹어셈블리와 OPFS(Origin Private File System)가 마련했다. 이 기술 덕분에 자바스크립트로 데이터베이스를 새로 구현하는 대신, 이미 검증된 엔진을 클라이언트로 직접 포팅할 수 있게 됐다.
고속 파일 시스템, OPFS
다소 생소한 브라우저 사양처럼 보이지만, OPFS는 현대 로컬 퍼스트 아키텍처에서 핵심적인 역할을 맡는다. WASM이 런타임을 제공한다면, OPFS는 파일 시스템을 담당한다.
OPFS는 브라우저가 사용자 하드 드라이브에 직접, 그리고 고성능으로 접근할 수 있도록 지원한다. 전체 파일이나 객체를 통째로 읽고 써야 하는 인덱스드DB와 달리, OPFS는 임의 위치에 대한 랜덤 액세스 쓰기를 허용한다. 예를 들어 PG라이트 같은 데이터베이스는 1GB 파일 한가운데 있는 4KB 데이터 페이지만 수정할 수 있다. 파일 전체를 다시 쓸 필요가 없다. 서버급 데이터베이스를 브라우저에서 거의 네이티브에 가까운 성능으로 실행할 수 있게 하는 마지막 퍼즐 조각이다.
노SQL의 대안, RxDB
PG라이트가 ‘클라이언트 위의 SQL’을 대표한다면, RxDB(Reactive Database)는 그에 대응하는 노SQL 진영이다. RxDB는 오랫동안 실제 환경에서 사용돼 온 브라우저 내 NoSQL 데이터베이스 파우치DB의 계보를 잇는다.
PG라이트가 서버의 구조를 클라이언트로 옮기는 데 초점을 맞춘다면, RxDB는 현대적인 UI의 동작 방식에 주목한다. 이름의 Rx가 보여주듯 반응성(reactivity)을 중심에 둔다. 일반적인 데이터베이스에서는 쿼리를 실행해 결과를 반환받는다. 반면 RxDB에서는 쿼리를 ‘구독’한다.
// In RxDB, the database IS the state managerdb.todos.find().$.subscribe(todos => { render(todos);});동기화 엔진이 서버에서 새로운 데이터를 푸시하면 UI는 즉시 갱신된다. 리덕스(Redux)나 피니아(Pinia) 같은 상태 관리 라이브러리를 따로 둘 필요가 없다. 데이터베이스 자체가 반응형 상태의 원천이기 때문이다.
결론
브라우저는 더 이상 문서 뷰어나 단순한 터미널 인터페이스에 머물지 않는다. 다만 로컬 퍼스트 아키텍처는 우리가 익숙한 REST와 REST 유사 모델에서 크게 벗어나는 급진적 전환이다. 그만큼 새로운 복잡성도 수반한다.
런타임 통합(윈터TC)과 산업 수준의 로컬 데이터베이스(PG라이트와 RxDB)가 결합하면서 브라우저는 완전한 애플리케이션 플랫폼으로 도약할 가능성을 얻었다. 그러나 기존 방식을 단숨에 대체하지는 못할 것이다. 프로그래밍 세계에서 익숙함은 강력한 관성으로 작용한다.
로컬 퍼스트와 동기화 모델이 언젠가 JSON과 REST의 왕좌를 위협할 수는 있다. 다만 그 전에 실제 환경에서 충분한 실행 가능성을 입증해야 한다.
dl-itworldkorea@foundryco.com
관련자료
-
링크
-
이전
-
다음






