{ "version": "1.1", "id": "a8-cache-vs-session", "title": "재시작이 지우는 것과 남기는 것", "question": "롤링 재시작 뒤에도 로그인이 유지되는 이유는 무엇인가", "type": "architecture", "direction": "TB", "audience": [ "무중단 배포를 설계하는 운영 엔지니어" ], "summary": "캐시는 파드와 함께 사라지고 세션은 데이터베이스에 남는다. persistent-user-sessions 를 켜는 진짜 이유다.", "alt": "재시작으로 Infinispan 캐시가 0 이 되지만 PostgreSQL 의 세션 행은 그대로 남아 refresh 가 계속 통하는 구성.", "long_description": "롤링 재시작은 한 번에 한 파드씩 바꾼다. 파드가 죽으면 그 노드의 Infinispan sessions 캐시는 0 으로 초기화된다. 그러나 PostgreSQL 의 세션 행은 151개가 그대로 남았고 재시작 전에 발급한 refresh token 이 여전히 200 을 받는다. 전 구간 서비스 중단이 없었다. volatile 모드였다면 같은 재시작에서 400 Session not active 가 되어 전원 로그아웃이 된다.", "source_context": { "document": "docs/keycloak-session-store/final/document.md", "document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe", "anchor": { "kind": "heading", "value": "A-8 · 롤링 재시작 — 세션은 살아남고 캐시만 사라진다", "line": 272 } }, "composition": { "profile": "component-flow", "diagram_only": true, "reference_ids": [ "payment-event-flow" ], "rationale": "무엇이 사라지고 무엇이 남는가가 지배적 질문이다. 저장 위치의 분기이므로 component-flow 를 골랐다." }, "groups": [], "nodes": [ { "id": "restart", "label": "롤링 재시작", "kind": "process", "role": "source", "emphasis": "primary", "description": "한 번에 한 파드씩 교체한다.", "details": [ "kubectl rollout restart" ], "evidence": [ { "start_line": 270, "end_line": 274 } ], "assumption": false }, { "id": "cache", "label": "Infinispan sessions 캐시", "kind": "component", "role": "target", "emphasis": "warning", "description": "파드와 함께 사라진다.", "details": [ "entries_unique → 0" ], "evidence": [ { "start_line": 270, "end_line": 278 } ], "assumption": false }, { "id": "db", "label": "PostgreSQL 세션 행", "kind": "datastore", "role": "target", "emphasis": "primary", "description": "재시작과 무관하다.", "details": [ "151 → 151" ], "evidence": [ { "start_line": 270, "end_line": 278 } ], "assumption": false }, { "id": "refresh", "label": "재시작 전 발급한 refresh token", "kind": "component", "role": "target", "emphasis": "primary", "description": "여전히 통한다.", "details": [ "200" ], "evidence": [ { "start_line": 270, "end_line": 278 } ], "assumption": false } ], "edges": [ { "id": "r-c", "from": "restart", "to": "cache", "label": "캐시 초기화", "kind": "write", "evidence": [ { "start_line": 270, "end_line": 278 } ], "assumption": false }, { "id": "r-db", "from": "restart", "to": "db", "label": "변경 없음", "kind": "read", "evidence": [ { "start_line": 270, "end_line": 278 } ], "assumption": false }, { "id": "db-rt", "from": "db", "to": "refresh", "label": "세션 조회", "kind": "read", "evidence": [ { "start_line": 270, "end_line": 278 } ], "assumption": false } ], "legend": [], "metadata": { "rationale": "캐시와 세션을 분리해 그렸다. 이 분리가 없으면 재시작 후 로그인이 유지되는 이유를 설명할 수 없다." } }