From a2f749292a6f57f2cf1d58d1775ab05585c82616 Mon Sep 17 00:00:00 2001 From: DongHyeonka Date: Fri, 4 Sep 2026 21:37:00 +0900 Subject: [PATCH] docs: add architecture diagrams for the three follow-up experiments Each of A-7a, B-7a and D-4a had the concepts, procedure, commands and terminal evidence but no diagram, which the rest of the series carries. a7a-cache-temperature.svg the three cache states and the SQL each issues b7a-orphan-lifecycle.svg ticket structure, accumulation across two rotations, and why TTL is the only signal d4a-hook-timeline.svg the 38m25s gap against the 1-2s one, on one axis Co-Authored-By: Claude Opus 5 --- docs/diagrams/a7a-cache-temperature.svg | 70 +++++++++++++++++++++++ docs/diagrams/b7a-orphan-lifecycle.svg | 74 +++++++++++++++++++++++++ docs/diagrams/d4a-hook-timeline.svg | 57 +++++++++++++++++++ docs/experiment-a7a-volatile-cause.md | 8 +++ docs/experiment-b7a-orphan-session.md | 8 +++ docs/experiment-d4a-deploy-hook.md | 8 +++ 6 files changed, 225 insertions(+) create mode 100644 docs/diagrams/a7a-cache-temperature.svg create mode 100644 docs/diagrams/b7a-orphan-lifecycle.svg create mode 100644 docs/diagrams/d4a-hook-timeline.svg diff --git a/docs/diagrams/a7a-cache-temperature.svg b/docs/diagrams/a7a-cache-temperature.svg new file mode 100644 index 0000000..2ab6538 --- /dev/null +++ b/docs/diagrams/a7a-cache-temperature.svg @@ -0,0 +1,70 @@ + + + + + + + +A-7a — volatile + DB 정지의 결과는 「무엇을 하느냐」가 아니라 「캐시가 더운가」로 갈린다 +문장 로깅(log_statement=all)으로 측정 · 세 상태 모두 재현 + + +로그인이 쏘는 SQL + +0개 — realm·사용자·클라이언트가 전부 캐시 +MARK_LOGIN_START / MARK_LOGIN_END 사이가 비어 있다 +volatile 이라 세션 쓰기도 없다 + + +refresh 가 쏘는 SQL + +select cscme1_0.SCOPE_ID from CLIENT_SCOPE_CLIENT +where CLIENT_ID=$1 and DEFAULT_SCOPE=$2 ('f' = optional) +★ REVOKED_TOKEN 은 한 번도 나오지 않는다 — A-7 의 가설은 틀렸다 +그리고 첫 refresh 만 쏜다. 이후 3회는 SQL 0건 = 캐시됨 + +그래서 같은 설정이 세 가지 답을 낸다 — PostgreSQL 정지 시 + + +① 완전 냉시동 +재시작 직후, 아무것도 안 함 +로그인 400 refresh 400 +select ce1_0.ID from CLIENT +클라이언트 조회조차 캐시에 없다 + + +② CLIENT 만 더움 +로그인 1회 뒤 · ← A-7 이 본 상태 +로그인 200 refresh 500 +CLIENT_SCOPE_CLIENT 조회 실패 +Keycloak 로그가 이 SQL 을 직접 지목 + + +③ 완전히 더움 +refresh 3회로 캐시를 채운 뒤 +로그인 200 refresh 200 +SQL 0건 — DB 를 아예 안 본다 +A-7 의 표와 정반대 + + + +로그인 1회 +refresh 3회 + + +남기는 것 +· A-7 의 표에는 조건이 빠져 있었다 — 「volatile 이면 DB 없이 로그인된다」도 냉시동에서는 거짓이다 +· 상태가 결과를 바꾸는데 그 상태가 안 보인다. A-1 의 conntrack 과 같은 계열의 함정이다 + diff --git a/docs/diagrams/b7a-orphan-lifecycle.svg b/docs/diagrams/b7a-orphan-lifecycle.svg new file mode 100644 index 0000000..14894c2 --- /dev/null +++ b/docs/diagrams/b7a-orphan-lifecycle.svg @@ -0,0 +1,74 @@ + + + + + + + +B-7a — 고아 세션은 지울 수 있다. oauth2-proxy 가 못 할 뿐이다 +회전 2회 측정 · Redis + oauth2-proxy 로그 + 브라우저 + +왜 프록시는 못 지우는가 — 티켓의 구조 + +쿠키에 담기는 것 = 티켓 + +세션 ID → Redis 키 이름 + +암호화 키 → 값 복호화 +티켓 전체가 cookie secret 으로 암호화되어 있다 + + +secret 을 바꾸면 +티켓을 못 연다 → 세션 ID 조차 못 읽는다 +→ 어느 Redis 키를 지울지 모른다 +Error removing session: error decoding ticket to clear session + + +회전할 때마다 누적한다 + + + +1차 회전 11:29:56 +2차 회전 11:33:27 + + +세션 A + +A 는 고아 · TTL 만료까지 남는다 + + +세션 B (1차 회전 후 생성) + +B 도 고아가 된다 + +세션 C (2차 회전 후 생성) +회전 1회 = 그 시점 로그인 사용자 수만큼의 고아 + + +Redis 만 보고는 구분할 수 없다 +이름 _oauth2_proxy-<불투명한 32자 hex> (동일 형식) +type string (동일) +크기 3510 바이트 (바이트까지 동일) +값 암호화됨 (읽을 수 없다) +→ 다른 것은 TTL 하나뿐이다 + + +그래서 TTL 이 정리 규칙이 된다 +--cookie-refresh 가 없어 TTL 이 갱신되지 않는다 (refresh:disabled) +→ TTL 은 생성 시각의 정확한 함수다 + +생성시각 = 지금 − (cookie-expire − TTL) +이 값이 회전 시각보다 이르면 고아. 검증: 역산 11:30:26 vs 로그 11:30:27 — 1초 오차 + diff --git a/docs/diagrams/d4a-hook-timeline.svg b/docs/diagrams/d4a-hook-timeline.svg new file mode 100644 index 0000000..92ecf37 --- /dev/null +++ b/docs/diagrams/d4a-hook-timeline.svg @@ -0,0 +1,57 @@ + + + + + + + +D-4a — deploy 훅 하나로 38분 25초가 1~2초가 된다 +시각은 전부 실제 UTC (test-server 시계에서 106초 보정) + + +D-4 — 훅이 없을 때 + + + + +옛 인증서를 계속 서빙 — 428회 관측 +08:20:27 디스크 기록 +08:58:52 사람이 nginx -s reload +2305초 = 38분 25초 +아무도 reload 하지 않았다면 다음 nginx 재시작까지 = 사실상 무기한 + + +D-4a — deploy 훅을 넣었을 때 + + + + +12:27:49.05 발급 (SCT — CT 로그의 독립 시계) +12:27:50 nginx -t · 새 워커 37252 · 12:27:51 reload +1~2초, 자동 +certbot 이 파일을 쓴 직후 같은 실행 안에서 deploy 훅을 부른다 — 사람이 개입할 자리가 없다 + + +판정은 문구가 아니라 워커 PID 로 +master 585 → 585 (유지) +worker 28829 → 37252 (교체 = reload 됨) +nginx 는 인증서를 기동 시 읽어 메모리에 든다 + + +★ 함정 — 성공을 실패로 오독한다 +Hook 'deploy-hook' ran with error output: + [warn] could not build optimal types_hash … +nginx 경고가 stderr 로 나갔을 뿐. 내용은 test is successful + diff --git a/docs/experiment-a7a-volatile-cause.md b/docs/experiment-a7a-volatile-cause.md index a68e563..484d58c 100644 --- a/docs/experiment-a7a-volatile-cause.md +++ b/docs/experiment-a7a-volatile-cause.md @@ -9,6 +9,14 @@ A-7 이 **가설로 남긴 것**을 확정하는 실험이다. 확정해 보니 --- +## 구조 + +![A-7a — 캐시 온도가 결과를 가른다](diagrams/a7a-cache-temperature.svg) + +> 다이어그램 규약은 [`diagrams/_style.md`](diagrams/_style.md). + +--- + ## 0. 결론부터 | 확인 | 결과 | diff --git a/docs/experiment-b7a-orphan-session.md b/docs/experiment-b7a-orphan-session.md index e806726..7a009f0 100644 --- a/docs/experiment-b7a-orphan-session.md +++ b/docs/experiment-b7a-orphan-session.md @@ -9,6 +9,14 @@ B-7 이 **「★ 지우지 못했다」** 로 남긴 자리를 잰다. --- +## 구조 + +![B-7a — 고아 세션의 발생·누적·정리](diagrams/b7a-orphan-lifecycle.svg) + +> 다이어그램 규약은 [`diagrams/_style.md`](diagrams/_style.md). + +--- + ## 0. 결론부터 | 물음 | 답 | diff --git a/docs/experiment-d4a-deploy-hook.md b/docs/experiment-d4a-deploy-hook.md index d911fc7..e92461a 100644 --- a/docs/experiment-d4a-deploy-hook.md +++ b/docs/experiment-d4a-deploy-hook.md @@ -10,6 +10,14 @@ D-4 는 결함을 찾고 **처방을 적어두고 검증하지 않았다.** --- +## 구조 + +![D-4a — 훅 유무에 따른 갱신→서빙 타임라인](diagrams/d4a-hook-timeline.svg) + +> 다이어그램 규약은 [`diagrams/_style.md`](diagrams/_style.md). + +--- + ## 0. 결론부터 | 확인 | 결과 |