21.6.1.3 콜드 스타트(Cold Start) 대형 스토리지 분산 쿼리 및 혼합 패치(Patching) 로직

21.6.1.3 콜드 스타트(Cold Start) 대형 스토리지 분산 쿼리 및 혼합 패치(Patching) 로직

초고속 메모이제이션(React.memo) 프론트엔드 방벽(21.6.1.2장)과 서버의 Node.js 중계기(21.6.1.1장)가 구축되었다면 시스템은 미친 속도의 실시간 푸시(Real-time Push) 스트림을 견뎌낼 수 있다.
그런데 이 아름다운 아키텍처는 브라우저를 껐다가 다시 켜서 관제탑을 최초로 진입하는 시점(Cold Start)에 치명적인 기능적 결함(Defect)을 맞이하게 된다.

막 브라우저에 접속한 클라이언트(React) 화면은 하얀 백지다. 그리고 Zenoh Pub/Sub 특성상 데이터는 누군가 로봇이 상태값(Pose)을 “갱신하여 쏴줄 때만” 허공을 건너온다. 어느 구석에 박힌 로봇 3번이 하루 종일 그 자리에서 가만히 있어서 데이터를 갱신(Publish)하지 않고 있다면?
관제 시스템 관리자는 영원히 그 로봇 3번이 지도 위 어느 산골짜기에 있는지 모르게 되는 저주에 빠진다 (Initial Blindness).
본 절에서는 초기 진입 찰나의 공백을 분쇄하기 위해 거대한 스토리지 플러그인 쿼리(Fetch) 강하 작전과, 이후 이어지는 실시간 푸시(Push) スト림을 하나의 웅덩이로 녹여버리는 초기-실시간 혼합 패치(Mixing Patch) 전술을 갈파한다.

1. Pub/Sub 이데올로기의 구조적 기억 상실(Amnesia)

Zenoh 핵심 엔진은 데이터를 들고 있지 않는다. 지나가는 데이터만 중계할 뿐이다 (Stateless).
이 때문에 관제 프론트엔드(React)는 켜자마자 telemetry/robot_*/pose 섭스크라이버를 박아보았자, 로봇이 스스로 깨어나 “나 살아있다“며 신호를 쏴 줄 때까지 하염없는 눈뜬장님이 되어야 한다(Cold Start Delay).

스웜 로봇이 1만 대라면 1만 대가 다 한 번씩 패킷을 쏴 줘야 대시보드의 화면 1장이 완성되는 식이다. 이것은 재난이다. 초기 진입자는 무조건 과거의 마지막 흔적 잔재(Last Known Status)를 단 0.1초 만에 풀사이즈 스냅샷(Full Snapshot)으로 내려받아 바닥에 박아놔야만 한다.

2. InfluxDB (Storage Plugin) 대상 대규모 분산 쿼리(Query) 백도어 강타

이 빈칸을 채우기 위해, 브라우저가 접속하는 Node.js Gateway 의 로직은 켜짐과 동시에 Sub 안테나를 올리지만, 그 즉시 Zenoh Queryable (GET) 펄스를 거대 스토리지 데몬(InfluxDB Storage Plugin, 13.9.4.2장)을 향해 냅다 찔러넣어야 한다!

// [Node.js Gateway의 콜드 스타트(Cold Start) 스냅샷 쿼리 런북]

// 1. 브로커가 켜지면 무작정 1만 개 로봇의 "가장 마지막 흔적"을 보관소에 요구한다!
const session = await zenoh.open();

// Push 망이 아니라, RESTful 모델의 GET 쿼리(RPC) 망을 찌른다.
// Zenoh 라우터 뒤에 숨어있는 InfluxDB 플러그인이 과거의 덤프를 게워내 줄 것이다.
const replies = await session.get("telemetry/robot_*/pose");

for await (const reply of replies) {
    const robotId = extractId(reply.keyExpr);
    // 2. 이 거대한 초기(Init) 스냅샷으로 내 백엔드 Map의 텅 빈 바닥 공사를 단번에 끝마친다!
    robotStates.set(robotId, JSON.parse(reply.ok.payload.toString()));
}

// 3. 바닥 공사(Snapshot)가 끝났으니, 이제부터 들어오는 실시간 데이터(Sub)를 
// 이 단단한 바닥 위에 차곡차곡 덮어씌움(Patching) 해나간다.
session.declareSubscriber("telemetry/robot_*/pose", (sample) => {
    // ... 기존 처리 로직 (Map Update)
});

결과적으로, Zenoh Storage 데몬 코어가 자신이 장판 밑에 모아두었던 1만 대의 과거 JSON 문자열 덩어리들을 HTTP GET 혹은 RPC 쿼리의 응답치 바이트(Payload)로 역류시켜 한 번에 폭우처럼 Node.js 쪽으로 밀어내려 준다.

3. 오버레이 패치(Patching Overlay)의 궁극적 환영술

이 “바닥 긁기(Cold Fetch)” 전략 덕분에, React 클라이언트가 웹 브라우저를 처음 켜는 시점의 통치 시그널은 이렇게 완성된다.

  1. [T=0s] 접속: 관제자의 브라우저 WebSocket 이 Node.js 에 연결된다.
  2. [T=0.1s] 거대 덤프 융단 폭격 (Query Base): Node.js 가 Zenoh Storage 에서 끌어모은 1만 대 로봇의 “과거 궤적 스냅샷 거대 JSON” 을 클라이언트로 일시불 폭격(Initial Sync)하여 던진다. 브라우저 지도는 0.1초 만에 1만 대의 점이 번쩍! 하며 풀(Full) 컬러 렌더링에 도달한다! (눈뜬장님 해결)
  3. [T=1.0s ~] 단편 패치 주입 (Sub Stream Overlay): 이후 1초마다, 실제로 움직여서 “위치가 바뀐 놈” 들의 작은 JSON 파편들만(Delta Updates) WebSocket 을 타고 넘어오며 기존 Zustand 스토어의 값 위를 예쁘게 덮어쓴다(Patch/Overwrite).

과거 기억 저장소(Storage Get)의 무겁지만 확실한 동기식 덩어리와, 현재 진행형 스트림(Router Sub)의 가볍고 민첩한 비동기 파편들을 프론트엔드의 State Map 이라는 한 그릇 안에서 아무런 이질감 없이 융해시켜버리는 기만술. 런타임의 푸시(Push) 이데올로기와 데이터베이스의 풀(Pull) 이데올로기를 중간 Node.js 중계기의 타임라인(Lifecycle) 한점에서 강제 합체시켜버린 것, 이것이야말로 실시간 분산 아키텍처 관제의 공포인 콜드 스타트 공백(Blindness)을 영구 삭제하는 필승의 통치술이다.