{ "version": "1.1", "id": "cache-temperature-outcomes", "title": "캐시 온도가 결과를 가른다", "question": "volatile 에서 DB 를 세우면 로그인과 refresh 는 어떻게 되는가", "type": "architecture", "direction": "TB", "audience": [ "옛 방식 Keycloak 의 장애 내성을 가늠하려는 엔지니어" ], "summary": "같은 설정이 캐시 온도만으로 400, 500, 200 세 가지 답을 낸다. 무엇을 하느냐가 아니라 그 경로가 이미 캐시를 채웠느냐가 결정한다.", "alt": "냉시동에서는 클라이언트 조회가, 반쯤 더운 상태에서는 스코프 조회가 데이터베이스에 닿아 실패하고, 완전히 더운 상태에서는 어느 쪽도 닿지 않는 구성.", "long_description": "volatile 모드에서 로그인은 SQL 을 0개 쏜다. refresh 는 딱 한 문장을 쏘는데 CLIENT_SCOPE_CLIENT 의 선택적 스코프 조회이며, 그것도 첫 번째만 쏘고 이후 캐시된다. 그래서 DB 를 세웠을 때 완전 냉시동이면 클라이언트 조회부터 실패해 로그인이 400 이고, CLIENT 캐시만 더우면 refresh 가 500 이며, 완전히 더우면 둘 다 200 이다. A-7 이 표에 적은 것은 그 사이의 한 상태였다.", "source_context": { "document": "docs/keycloak-session-store/final/document.md", "document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe", "anchor": { "kind": "heading", "value": "A-7 · A-7a — 전부 뒤집는 설정 하나, 그리고 그 표에도 조건이 있었다", "line": 283 } }, "composition": { "profile": "component-flow", "diagram_only": true, "reference_ids": [ "payment-event-flow" ], "rationale": "어느 조회가 캐시에 있고 어느 것이 데이터베이스에 닿는가가 지배적 질문이다. 조회 경로의 분기이므로 component-flow 를 골랐다." }, "groups": [], "nodes": [ { "id": "request", "label": "로그인 · refresh 요청", "kind": "actor", "role": "source", "emphasis": "primary", "description": "같은 명령이 캐시 상태에 따라 다른 답을 받는다.", "details": [], "evidence": [ { "start_line": 284, "end_line": 296 } ], "assumption": false }, { "id": "client-lookup", "label": "CLIENT 조회", "kind": "process", "role": "control", "emphasis": "warning", "description": "냉시동에서 여기서 실패한다.", "details": [ "select ce1_0.ID from CLIENT" ], "evidence": [ { "start_line": 306, "end_line": 312 } ], "assumption": false }, { "id": "scope-lookup", "label": "CLIENT_SCOPE_CLIENT 조회", "kind": "process", "role": "control", "emphasis": "warning", "description": "refresh 만 쏘고 첫 번째만 쏜다.", "details": [ "DEFAULT_SCOPE='f'" ], "evidence": [ { "start_line": 284, "end_line": 292 } ], "assumption": false }, { "id": "db", "label": "PostgreSQL", "kind": "datastore", "role": "target", "emphasis": "primary", "description": "세운 상태다. 여기 닿는 조회만 실패한다.", "details": [ "캐시 미스 시에만 도달" ], "evidence": [ { "start_line": 296, "end_line": 302 } ], "assumption": false } ], "edges": [ { "id": "r-c", "from": "request", "to": "client-lookup", "label": "클라이언트 확인", "kind": "read", "evidence": [ { "start_line": 306, "end_line": 312 } ], "assumption": false }, { "id": "c-s", "from": "client-lookup", "to": "scope-lookup", "label": "스코프 재계산", "kind": "read", "evidence": [ { "start_line": 284, "end_line": 292 } ], "assumption": false }, { "id": "s-db", "from": "scope-lookup", "to": "db", "label": "캐시 미스", "kind": "read", "evidence": [ { "start_line": 296, "end_line": 302 } ], "assumption": false } ], "legend": [], "metadata": { "rationale": "세 결과를 나열하는 대신 그 결과를 만드는 조회 두 개를 그렸다. 캐시가 그 조회를 삼키면 결과가 바뀐다." } }