Miscellaneous
IndexedDB 아키텍처: 다중 프로세스 접근 원리
웹 애플리케이션에서 IndexedDB는 Service Worker Process와 Renderer Process(메인 스레드가 실행되는 탭) 양쪽에서 모두 접근할 수 있는 유일한 영구 저장소입니다. 이러한 공유 접근이 가능한 이유는 localStorage와 근본적으로 다른 아키텍처 설계에 있습니다.
1. localStorage의 한계
localStorage는 서비스 워커 컨텍스트에서 사용할 수 없으며, 그 이유는 다음과 같습니다.
window객체 종속성:localStorage는window.localStorageAPI를 통해 노출됩니다.window객체는RendererProcess(탭)에만 존재하는 전역 객체이며,Service WorkerProcess에는window객체가 존재하지 않아 접근이 원천적으로 불가능합니다.- 동기(Synchronous) API:
localStorage는 동기식 API입니다. 만약 서비스 워커에서 이 API를 사용할 수 있게 허용한다면, 모든 백그라운드 작업을 처리하는 서비스 워커 스레드가 차단(blocking)되어 브라우저 전체의 성능에 심각한 영향을 미칠 수 있습니다.
2. IndexedDB의 아키텍처: IPC (프로세스 간 통신)
IndexedDB는 특정 프로세스의 메모리(Heap)에 저장되는 데이터가 아니며, 다음과 같은 브라우저의 핵심 아키텍처를 통해 작동합니다.
1. 관리 주체: 브라우저 프로세스 (Browser Process)
IndexedDB의 실제 데이터는 사용자의 디스크(Disk)에 파일 형태(LevelDB)로 저장됩니다. 이 디스크 파일에 직접 접근하여 데이터를 읽고 쓰는 유일한 주체는 브라우저의 핵심인 **브라우저 프로세스(Browser Process)**입니다.
모든 탭(Renderer Process)과 서비스 워커(Service Worker Process)는 이 데이터를 직접 관리하지 않습니다.
2. 접근 방식: 프로세스 간 통신 (IPC)
Renderer Process나 Service Worker Process에서 indexedDB.open() 같은 API를 호출할 때, 실제로는 해당 프로세스의 메모리에서 작업을 수행하는 것이 아닙니다.
- 비동기 요청:
IndexedDBAPI 호출은 브라우저의 저수준(low-level) IPC(Inter-Process Communication) 메커니즘을 통해 "브라우저 프로세스"에게 **비동기 메시지(Request)**를 전송합니다. - 중앙 관리: 브라우저 프로세스는 모든 프로 세스(여러 탭, 서비스 워커)로부터 받은 요청을 **중앙 큐(Queue)**에서 순서대로 관리합니다. 트랜잭션과 파일 잠금(Lock)을 보장하며 안전하게 디스크의 데이터를 처리합니다.
- 비동기 응답: 작업이 완료되면, 브라우저 프로세스는 다시 IPC를 통해 **결과 메시지(Response)**를 원래 요청했던 프로세스에게 돌려보냅니다.
3. 이벤트 루프와 태스크 큐 (Event Loop & Task Queue)
브라우저 프로세스로부터 반환된 IPC 결과 메시지는 해당 프로세스(Renderer 또는 SW)의 **태스크 큐(Task Queue, Macrotask Queue)**에 등록됩니다.
그러면 해당 프로세스의 **이벤트 루프(Event Loop)**가 이 태스크를 발견하고, onsuccess 콜백 함수를 실행하거나 관련 Promise를 resolve시킵니다.
결론적으로, IndexedDB는 브라우저의 핵심인 브라우저 프로세스가 중앙에서 관리하는 디스크 기반 저장소입니다. 모든 컨텍스트(탭, 서비스 워커)는 오직 비동기 IPC라는 표준화된 통신 채널을 통해서만 접근을 "요청"하고 "응답"받기 때문에, 여러 프로세스 간에 데이터를 안전하게 공유할 수 있습니다.
Service Worker의 수명 주기와 Web API (setInterval)
1. 문제의 배경: 역설(Paradox)
setInterval과 같은 Web API는 JS 메인 스레드의 콜 스택에서 직접 시간을 세지 않고, 브라우저 내부의 별도 메커니즘(타이머 관리 시스템)에게 "위임" 됩니다. 이 타이머 관리 시스템은 Renderer Process 내의 별도 스레드이거나 Browser Process의 일부일 수 있으며, 정확한 구현은 브라우저마다 다릅니다.
여기서 다음과 같은 논리적인 질문이 생깁니다.
"Service Worker(SW)의 실행 컨텍스트가 종료되더라도, 타이머를 위임받은 브라우저 내부 시스템은 살아있습니다. 그렇다면 왜
setInterval이 멈추는 것입니까? 타이머는 계속 돌고, 나중에 SW가 다시 살아났을 때 밀린 콜백을 처리해야 하는 것 아닙니까?"
이 질문의 답은 Task Queue(작업 큐) 가 작동하는 방식에 있습니다.
2. 핵심 원리: Task Queue는 실행 컨텍스트에 종속적입니다.
Task Queue(이벤트 큐)는 브라우저 전체에 하나만 존재하는 "공용 큐"가 아닙니다.
- 탭 1의 Renderer Process 는 "탭 1 전용 Task Queue" 를 가집니다.
- 탭 2의 Renderer Process 는 "탭 2 전용 Task Queue" 를 가집니다.
- Service Worker의 실행 컨텍스트 는 "SW 전용 Task Queue" 를 가집니다.
참고: Service Worker는 어디에서 실행되는가?
Chromium 기준으로 Service Worker는 반드시 독립적인 프로세스에서 실행되는 것이 아닙니다.
- 독립 프로세스: Site Isolation 정책 등에 의해 별도의 Renderer Process를 할당받아 실행될 수 있습니다.
- 기존 Renderer Process 내 별도 스레드 : 같은 origin의 Renderer Process 안에서 Worker 스레드로 실행될 수도 있습니다.
어느 경우든, Service Worker는 자신만의 실행 컨텍스트(Call Stack, Heap, Task Queue) 를 가지며, 이 컨텍스트가 종료되면 모든 것이 함께 사라집니다. 따라서 이 문서에서는 프로세스/스레드 구분 대신 "SW 실행 컨텍스트" 라는 표현을 사용합니다.
Web API에게 작업을 위임한다는 것은 "그냥 실행해"가 아니라, "작업이 끝나면 나의 전용 Task Queue에 콜백을 넣어줘" 라는 의미입니다.
3. setInterval이 멈추는 정확한 순서
-
[SW 실행 컨텍스트]
setInterval(myCallback, 1000)을 호출합니다.- 이것은 브라우저의 타이머 관리 시스템에게 보내는 요청입니다.
- 요청 내용: "1초마다
myCallback을 SW 전용 Task Queue에 배달해주세요."
-
[브라우저 타이머 시스템] "알겠습니다." (타이머 시작)
-
[SW 실행 컨텍스트] 현재 처리 중이던 이벤트(예:
install또는activate)를 완료하고 "유휴(Idle)" 상태가 됩니다. -
[Browser Process] Service Worker는 리소스 절약을 위해 "이벤트 기반"으로 작동하도록 설계되었습니다. Browser Process는 SW가 유휴 상태인 것을 확인하고, SW의 실행 컨텍스트를 강제로 종료(Terminate) 시킵니다.
-
[SW 실행 컨텍스트] 실행 컨텍스트가 종료되면서, 이 컨텍스트에 속해있던 Call Stack, Heap, 그리고 "SW 전용 Task Queue"가 모두 메모리에서 사라집니다.
-
[브라우저 타이머 시스템] (1초 뒤) "약속대로
myCallback을 SW 전용 Task Queue에 배달해야지." -
[브라우저 타이머 시스템] "...어? 배달할 주소(SW 전용 Task Queue)가 존재하지 않습니다."
-
[브라우저 타이머 시스템] 배달 대상을 잃은 타이머는 작업을 중단하거나 취소됩니다.
🍕 피자 배달 비유
setInterval은 10분마다 피자(myCallback)를 "A사무실" (SW 실행 컨텍스트)로 배달해달라고 주문하는 것과 같습니다.- "A사무실"이 갑자기 폐업해서 사라졌습니다.
- 피자 배달부(브라우저의 타이머 시스템)는 10분 뒤 "A사무실"에 도착했지만, 사무실 자체가 사라진 것을 확인합니다. 배달부는 피자를 버리고(작업 취소), 더 이상 "A사무실"로 배달을 오지 않습니다.
결론: setInterval은 Service Worker의 수명을 연장해주지 못합니다. 브라우저의 타이머 시스템이 멈추는 것이 아니라, 콜백을 전달받을 대상(Task Queue) 이 실행 컨텍스트 종료와 함께 사라지기 때문에 멈추는 것입니다.
4. 핵심 출처 (Sources)
-
Service Worker의 수명 주기 (MDN):
- https://www.w3.org/TR/service-workers/#service-worker-lifetime
- 내용: 이 문서, 특히 '수명 주기(Lifecycle)' 섹션에서는 서비스 워커가 이벤트를 처리하지 않을 때 "유휴(idle)" 상태가 되고 결국 "종료(terminated)" 된다고 명시하고 있습니다.
setInterval은 이 수명을 연장시키는 "이벤트"로 간주되지 않습니다.
-
이벤트 루프와 태스크 큐 (MDN):
- https://developer.mozilla.org/docs/Web/JavaScript/EventLoop
- 내용: 이 문서는 Web API(예:
setInterval)의 콜백이 어떻게 "태스크 큐(Task Queue)" 를 통해 처리되는지 설명합니다. 우리가 논의한 "배달 주소"가 바로 이 큐이며, 이 큐는 실행 컨텍스트와 생명 주기를 함께합니다.