Files
document-haness/docs/keycloak-session-store/final/.techviz/session-sharing-path/spec.json
T

172 lines
5.2 KiB
JSON

{
"version": "1.1",
"id": "session-sharing-path",
"title": "세션 공유가 실제로 지나는 경로",
"question": "두 Keycloak 노드가 같은 세션을 아는 것은 무엇 때문인가",
"type": "architecture",
"direction": "LR",
"audience": [
"Keycloak 을 다중 노드로 운영하는 백엔드 엔지니어"
],
"summary": "클러스터 뷰는 형성되지만 세션 엔트리는 노드 사이를 건너가지 않는다. 두 노드가 같은 답을 내놓는 경로는 PostgreSQL 이다.",
"alt": "keycloak-0 과 keycloak-1 이 각자 캐시를 갖고 PostgreSQL 을 함께 읽는 구성. 두 캐시 사이에는 세션 복제 경로가 없다.",
"long_description": "keycloak-0 과 keycloak-1 은 JGROUPS_PING 테이블을 통해 서로를 발견하고 클러스터 뷰를 형성한다. 그러나 sessions 캐시의 엔트리는 노드 사이로 복제되지 않으며, 각 노드는 자기가 처리한 로그인만 캐시한다. 노드 A 로 로그인한 세션을 노드 B 가 아는 이유는 노드 B 가 PostgreSQL 의 OFFLINE_USER_SESSION 을 직접 읽기 때문이고, 이는 반대편 노드가 날린 SQL 을 문장 로깅으로 잡아 확인했다.",
"source_context": {
"document": "docs/keycloak-session-store/final/document.md",
"document_sha256": "609353e10bfd37a9bbb6a79ecf2a32f3d3c02d5d161879a14ad4713e49e7e5e8",
"anchor": {
"kind": "heading",
"value": "그런데 첫 실험에서 전제가 무너졌다",
"line": 33
}
},
"composition": {
"profile": "component-flow",
"diagram_only": true,
"reference_ids": [
"payment-event-flow"
],
"rationale": "세 구성 요소 사이에서 어느 경로가 실제로 존재하고 어느 경로가 존재하지 않는지가 이 절의 지배적 질문이다. 시간 순서가 아니라 경로의 유무가 핵심이므로 component-flow 를 골랐다."
},
"groups": [],
"nodes": [
{
"id": "keycloak-0",
"label": "keycloak-0",
"kind": "service",
"role": "source",
"emphasis": "primary",
"description": "로그인을 처리하고 자기 sessions 캐시에만 엔트리를 남긴다.",
"details": [
"자기 처리분만 캐시"
],
"evidence": [
{
"start_line": 49,
"end_line": 51
}
],
"assumption": false
},
{
"id": "postgres",
"label": "PostgreSQL",
"kind": "datastore",
"role": "store",
"emphasis": "primary",
"description": "OFFLINE_USER_SESSION 에 세션 행을 보관한다. 두 노드가 같은 행을 본다.",
"details": [
"OFFLINE_USER_SESSION",
"offline_flag='0'",
"두 노드 공용"
],
"evidence": [
{
"start_line": 48,
"end_line": 52
}
],
"assumption": false
},
{
"id": "keycloak-1",
"label": "keycloak-1",
"kind": "service",
"role": "target",
"emphasis": "primary",
"description": "다른 노드가 만든 세션을 캐시로 받지 않고 데이터베이스에서 읽는다.",
"details": [
"refresh 시 DB 조회"
],
"evidence": [
{
"start_line": 48,
"end_line": 51
}
],
"assumption": false
},
{
"id": "jgroups-ping",
"label": "JGROUPS_PING",
"kind": "datastore",
"role": "support",
"emphasis": "muted",
"description": "노드가 서로를 발견하는 자리. 여기 등록되어 있다는 것과 세션이 복제된다는 것은 다른 사건이다.",
"evidence": [
{
"start_line": 44,
"end_line": 46
}
],
"assumption": false,
"details": [
"노드 둘 등록",
"세션 복제 아님"
]
}
],
"edges": [
{
"id": "k0-writes",
"from": "keycloak-0",
"to": "postgres",
"label": "세션 INSERT",
"kind": "write",
"evidence": [
{
"start_line": 49,
"end_line": 52
}
],
"assumption": false
},
{
"id": "k1-reads",
"from": "keycloak-1",
"to": "postgres",
"label": "세션 SELECT",
"kind": "read",
"evidence": [
{
"start_line": 48,
"end_line": 50
}
],
"assumption": false
},
{
"id": "k0-discovery",
"from": "keycloak-0",
"to": "jgroups-ping",
"label": "멤버 등록",
"kind": "write",
"evidence": [
{
"start_line": 44,
"end_line": 45
}
],
"assumption": false
},
{
"id": "k1-discovery",
"from": "keycloak-1",
"to": "jgroups-ping",
"label": "멤버 등록",
"kind": "write",
"evidence": [
{
"start_line": 44,
"end_line": 45
}
],
"assumption": false
}
],
"legend": [],
"metadata": {
"rationale": "클러스터 형성과 세션 복제를 한 그림에서 분리했다. 발견(JGROUPS_PING)과 공유(OFFLINE_USER_SESSION)가 같은 데이터베이스 안의 다른 테이블이라는 점이 이 절의 오해가 생기는 자리다."
}
}