refactor: 문서 개선 중

This commit is contained in:
donghyeon-ka
2026-09-21 14:30:55 +09:00
parent c93cdea150
commit 805a18f486
1497 changed files with 525837 additions and 59152 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -8,16 +8,16 @@
"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 을 문장 로깅으로 잡아 확인했다.",
"summary": "두 Keycloak 노드가 서로를 발견하는 경로는 JGROUPS_PING이고, 다른 노드의 세션을 아는 실제 공유 경로는 PostgreSQL OFFLINE_USER_SESSION이다.",
"alt": "Keycloak replica 두 개에서 JGROUPS_PING으로는 멤버 발견이, OFFLINE_USER_SESSION으로는 세션 저장과 조회가 갈라지는 두 경로.",
"long_description": "keycloak-0과 keycloak-1은 JGROUPS_PING을 통해 서로를 발견하지만 sessions cache 엔트리를 서로 복제지 않는다. 다른 노드가 만든 세션을 알아야 할 때는 PostgreSQL OFFLINE_USER_SESSION을 직접 읽는다. discovery와 session sharing은 같은 데이터베이스 안에서도 다른 책임이다.",
"source_context": {
"document": "docs/keycloak-session-store/final/document.md",
"document_sha256": "609353e10bfd37a9bbb6a79ecf2a32f3d3c02d5d161879a14ad4713e49e7e5e8",
"document_sha256": "28aef96a2bbb94fbb10ade26a71238fee62a5a4d9fa6e7749ae98cfd0a65e560",
"anchor": {
"kind": "heading",
"value": "그런데 첫 실험에서 전제가 무너졌다",
"line": 33
"line": 64
}
},
"composition": {
@@ -26,139 +26,93 @@
"reference_ids": [
"payment-event-flow"
],
"rationale": "세 구성 요소 사이에서 어느 경로가 실제로 존재하고 어느 경로가 존재하지 않는지가 이 절의 지배적 질문이다. 시간 순서가 아니라 경로의 유무가 핵심이므로 component-flow 를 골랐다."
"rationale": "두 replica를 반복해서 그리지 않고 Keycloak replica 집합에서 발견 테이블과 세션 테이블로 갈리는 두 책임을 분리한다."
},
"groups": [],
"nodes": [
{
"id": "keycloak-0",
"label": "keycloak-0",
"id": "replicas",
"label": "Keycloak replica 2개",
"kind": "service",
"role": "source",
"emphasis": "primary",
"description": "로그인을 처리하고 자기 sessions 캐시에만 엔트리를 남긴다.",
"description": "keycloak-0과 keycloak-1은 각자 sessions cache를 갖고 같은 PostgreSQL을 사용한다.",
"details": [
"자기 처리분만 캐시"
"keycloak-0 · keycloak-1",
"sessions cache는 각자"
],
"evidence": [
{
"start_line": 49,
"end_line": 51
"start_line": 75,
"end_line": 81
}
],
"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",
"id": "discovery",
"label": "JGROUPS_PING",
"kind": "datastore",
"role": "support",
"emphasis": "muted",
"description": "노드가 서로를 발견하는 자리. 여기 등록되어 있다는 것과 세션이 복제된다는 것은 다른 사건이다.",
"evidence": [
{
"start_line": 44,
"end_line": 46
}
],
"assumption": false,
"role": "target",
"emphasis": "normal",
"description": "노드 discovery와 membership을 위한 테이블이다. 세션 엔트리 복제 경로가 아니다.",
"details": [
"노드 둘 등록",
"세션 복제 아님"
]
"discovery만 담당"
],
"evidence": [
{
"start_line": 75,
"end_line": 75
}
],
"assumption": false
},
{
"id": "session-store",
"label": "OFFLINE_USER_SESSION",
"kind": "datastore",
"role": "target",
"emphasis": "primary",
"description": "다른 노드가 만든 세션을 직접 읽는 실제 공유 경로다.",
"details": [
"keycloak-0 INSERT",
"keycloak-1 SELECT"
],
"evidence": [
{
"start_line": 78,
"end_line": 81
}
],
"assumption": false
}
],
"edges": [
{
"id": "k0-writes",
"from": "keycloak-0",
"to": "postgres",
"label": "세션 INSERT",
"id": "discovery-path",
"from": "replicas",
"to": "discovery",
"label": "멤버 발견",
"kind": "write",
"evidence": [
{
"start_line": 49,
"end_line": 52
"start_line": 75,
"end_line": 75
}
],
"assumption": false
},
{
"id": "k1-reads",
"from": "keycloak-1",
"to": "postgres",
"label": "세션 SELECT",
"kind": "read",
"id": "session-path",
"from": "replicas",
"to": "session-store",
"label": "세션 저장 · 조회",
"kind": "data",
"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
"start_line": 78,
"end_line": 81
}
],
"assumption": false
@@ -166,6 +120,6 @@
],
"legend": [],
"metadata": {
"rationale": "클러스터 형성과 세션 복제를 한 그림에서 분리했다. 발견(JGROUPS_PING)과 공유(OFFLINE_USER_SESSION)가 같은 데이터베이스 안의 다른 테이블이라는 점이 이 절의 오해가 생기는 자리다."
"rationale": "replica 두 개를 각각 두 저장소와 연결하면 선만 교차하고 핵심이 흐려진다. replica 집합에서 발견과 세션 공유 책임이 갈라지는 것으로 압축했다."
}
}