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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e9baac21d5
commit
a2f749292a
@@ -0,0 +1,70 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 470" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,sans-serif">
|
||||
<style>
|
||||
.box{fill:#fff;stroke:#8c959f;stroke-width:1.4;rx:6}
|
||||
.dead{fill:#fff5f5;stroke:#cf222e;stroke-width:1.6;stroke-dasharray:5 3;rx:6}
|
||||
.ok{fill:#f6fdf6;stroke:#1a7f37;stroke-width:1.6;rx:6}
|
||||
.warn{fill:#fff8f0;stroke:#bf8700;stroke-width:1.5;rx:6}
|
||||
.t{font-size:12px;fill:#1f2328}
|
||||
.tb{font-size:12.5px;fill:#1f2328;font-weight:600}
|
||||
.s{font-size:10.5px;fill:#656d76}
|
||||
.ttl{font-size:14px;fill:#1f2328;font-weight:600}
|
||||
.r{stroke:#cf222e;stroke-width:1.6;fill:none}
|
||||
.g{stroke:#1a7f37;stroke-width:1.6;fill:none}
|
||||
.k{stroke:#8c959f;stroke-width:1.3;fill:none}
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#8c959f"/></marker>
|
||||
<marker id="ar" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#cf222e"/></marker>
|
||||
<marker id="ag" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#1a7f37"/></marker>
|
||||
</defs>
|
||||
<text x="20" y="26" class="ttl">A-7a — volatile + DB 정지의 결과는 「무엇을 하느냐」가 아니라 「캐시가 더운가」로 갈린다</text>
|
||||
<text x="20" y="44" class="s">문장 로깅(log_statement=all)으로 측정 · 세 상태 모두 재현</text>
|
||||
|
||||
<rect x="20" y="66" width="380" height="120" class="box"/>
|
||||
<text x="34" y="88" class="tb">로그인이 쏘는 SQL</text>
|
||||
<rect x="36" y="100" width="348" height="34" class="ok"/>
|
||||
<text x="48" y="122" class="t">0개 — realm·사용자·클라이언트가 전부 캐시</text>
|
||||
<text x="36" y="152" class="s">MARK_LOGIN_START / MARK_LOGIN_END 사이가 비어 있다</text>
|
||||
<text x="36" y="170" class="s">volatile 이라 세션 쓰기도 없다</text>
|
||||
|
||||
<rect x="440" y="66" width="400" height="120" class="box"/>
|
||||
<text x="454" y="88" class="tb">refresh 가 쏘는 SQL</text>
|
||||
<rect x="456" y="100" width="368" height="34" class="warn"/>
|
||||
<text x="466" y="115" class="t">select cscme1_0.SCOPE_ID from CLIENT_SCOPE_CLIENT</text>
|
||||
<text x="466" y="129" class="s">where CLIENT_ID=$1 and DEFAULT_SCOPE=$2 ('f' = optional)</text>
|
||||
<text x="454" y="152" class="s">★ REVOKED_TOKEN 은 한 번도 나오지 않는다 — A-7 의 가설은 틀렸다</text>
|
||||
<text x="454" y="170" class="s">그리고 첫 refresh 만 쏜다. 이후 3회는 SQL 0건 = 캐시됨</text>
|
||||
|
||||
<text x="20" y="222" class="tb">그래서 같은 설정이 세 가지 답을 낸다 — PostgreSQL 정지 시</text>
|
||||
|
||||
<rect x="20" y="240" width="266" height="120" class="dead"/>
|
||||
<text x="34" y="262" class="tb">① 완전 냉시동</text>
|
||||
<text x="34" y="282" class="s">재시작 직후, 아무것도 안 함</text>
|
||||
<text x="34" y="306" class="t">로그인 <tspan fill="#cf222e" font-weight="600">400</tspan> refresh 400</text>
|
||||
<text x="34" y="328" class="s">select ce1_0.ID from CLIENT</text>
|
||||
<text x="34" y="344" class="s">클라이언트 조회조차 캐시에 없다</text>
|
||||
|
||||
<rect x="298" y="240" width="266" height="120" class="warn"/>
|
||||
<text x="312" y="262" class="tb">② CLIENT 만 더움</text>
|
||||
<text x="312" y="282" class="s">로그인 1회 뒤 · ← A-7 이 본 상태</text>
|
||||
<text x="312" y="306" class="t">로그인 200 refresh <tspan fill="#bf8700" font-weight="600">500</tspan></text>
|
||||
<text x="312" y="328" class="s">CLIENT_SCOPE_CLIENT 조회 실패</text>
|
||||
<text x="312" y="344" class="s">Keycloak 로그가 이 SQL 을 직접 지목</text>
|
||||
|
||||
<rect x="576" y="240" width="264" height="120" class="ok"/>
|
||||
<text x="590" y="262" class="tb">③ 완전히 더움</text>
|
||||
<text x="590" y="282" class="s">refresh 3회로 캐시를 채운 뒤</text>
|
||||
<text x="590" y="306" class="t">로그인 200 refresh <tspan fill="#1a7f37" font-weight="600">200</tspan></text>
|
||||
<text x="590" y="328" class="s">SQL 0건 — DB 를 아예 안 본다</text>
|
||||
<text x="590" y="344" class="s">A-7 의 표와 정반대</text>
|
||||
|
||||
<path d="M286 300 L294 300" class="k" marker-end="url(#a)"/>
|
||||
<path d="M564 300 L572 300" class="k" marker-end="url(#a)"/>
|
||||
<text x="292" y="290" class="s">로그인 1회</text>
|
||||
<text x="570" y="290" class="s">refresh 3회</text>
|
||||
|
||||
<rect x="20" y="384" width="820" height="66" class="box"/>
|
||||
<text x="34" y="406" class="tb">남기는 것</text>
|
||||
<text x="34" y="426" class="s">· A-7 의 표에는 조건이 빠져 있었다 — 「volatile 이면 DB 없이 로그인된다」도 냉시동에서는 거짓이다</text>
|
||||
<text x="34" y="442" class="s">· 상태가 결과를 바꾸는데 그 상태가 안 보인다. A-1 의 conntrack 과 같은 계열의 함정이다</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,74 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 500" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,sans-serif">
|
||||
<style>
|
||||
.box{fill:#fff;stroke:#8c959f;stroke-width:1.4;rx:6}
|
||||
.dead{fill:#fff5f5;stroke:#cf222e;stroke-width:1.6;stroke-dasharray:5 3;rx:6}
|
||||
.ok{fill:#f6fdf6;stroke:#1a7f37;stroke-width:1.6;rx:6}
|
||||
.warn{fill:#fff8f0;stroke:#bf8700;stroke-width:1.5;rx:6}
|
||||
.t{font-size:12px;fill:#1f2328}
|
||||
.tb{font-size:12.5px;fill:#1f2328;font-weight:600}
|
||||
.s{font-size:10.5px;fill:#656d76}
|
||||
.ttl{font-size:14px;fill:#1f2328;font-weight:600}
|
||||
.r{stroke:#cf222e;stroke-width:1.6;fill:none}
|
||||
.g{stroke:#1a7f37;stroke-width:1.6;fill:none}
|
||||
.k{stroke:#8c959f;stroke-width:1.3;fill:none}
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#8c959f"/></marker>
|
||||
<marker id="ar" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#cf222e"/></marker>
|
||||
<marker id="ag" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#1a7f37"/></marker>
|
||||
</defs>
|
||||
<text x="20" y="26" class="ttl">B-7a — 고아 세션은 지울 수 있다. oauth2-proxy 가 못 할 뿐이다</text>
|
||||
<text x="20" y="44" class="s">회전 2회 측정 · Redis + oauth2-proxy 로그 + 브라우저</text>
|
||||
|
||||
<text x="20" y="76" class="tb">왜 프록시는 못 지우는가 — 티켓의 구조</text>
|
||||
<rect x="20" y="88" width="400" height="86" class="box"/>
|
||||
<text x="34" y="110" class="t">쿠키에 담기는 것 = 티켓</text>
|
||||
<rect x="36" y="120" width="180" height="30" class="box"/>
|
||||
<text x="48" y="140" class="s">세션 ID → Redis 키 이름</text>
|
||||
<rect x="224" y="120" width="180" height="30" class="box"/>
|
||||
<text x="236" y="140" class="s">암호화 키 → 값 복호화</text>
|
||||
<text x="34" y="166" class="s">티켓 전체가 cookie secret 으로 암호화되어 있다</text>
|
||||
|
||||
<rect x="444" y="88" width="396" height="86" class="dead"/>
|
||||
<text x="458" y="110" class="tb">secret 을 바꾸면</text>
|
||||
<text x="458" y="130" class="s">티켓을 못 연다 → 세션 ID 조차 못 읽는다</text>
|
||||
<text x="458" y="148" class="s">→ 어느 Redis 키를 지울지 모른다</text>
|
||||
<text x="458" y="166" class="s">Error removing session: error decoding ticket to clear session</text>
|
||||
<path d="M424 131 L440 131" class="r" marker-end="url(#ar)"/>
|
||||
|
||||
<text x="20" y="208" class="tb">회전할 때마다 누적한다</text>
|
||||
<line x1="70" y1="256" x2="800" y2="256" class="k"/>
|
||||
<line x1="130" y1="244" x2="130" y2="268" stroke="#cf222e" stroke-width="2"/>
|
||||
<line x1="430" y1="244" x2="430" y2="268" stroke="#cf222e" stroke-width="2"/>
|
||||
<text x="92" y="288" class="s">1차 회전 11:29:56</text>
|
||||
<text x="392" y="288" class="s">2차 회전 11:33:27</text>
|
||||
|
||||
<rect x="70" y="224" width="60" height="16" class="ok"/>
|
||||
<text x="76" y="236" class="s">세션 A</text>
|
||||
<rect x="130" y="224" width="300" height="16" class="dead"/>
|
||||
<text x="150" y="236" class="s" fill="#cf222e">A 는 고아 · TTL 만료까지 남는다</text>
|
||||
<rect x="130" y="224" width="0" height="0"/>
|
||||
<rect x="150" y="304" width="280" height="16" class="ok"/>
|
||||
<text x="156" y="316" class="s">세션 B (1차 회전 후 생성)</text>
|
||||
<rect x="430" y="304" width="370" height="16" class="dead"/>
|
||||
<text x="450" y="316" class="s" fill="#cf222e">B 도 고아가 된다</text>
|
||||
<rect x="450" y="224" width="350" height="16" class="ok"/>
|
||||
<text x="456" y="236" class="s">세션 C (2차 회전 후 생성)</text>
|
||||
<text x="70" y="338" class="s">회전 1회 = 그 시점 로그인 사용자 수만큼의 고아</text>
|
||||
|
||||
<rect x="20" y="356" width="400" height="126" class="dead"/>
|
||||
<text x="34" y="378" class="tb">Redis 만 보고는 구분할 수 없다</text>
|
||||
<text x="34" y="400" class="s">이름 _oauth2_proxy-<불투명한 32자 hex> (동일 형식)</text>
|
||||
<text x="34" y="418" class="s">type string (동일)</text>
|
||||
<text x="34" y="436" class="s">크기 3510 바이트 (바이트까지 동일)</text>
|
||||
<text x="34" y="454" class="s">값 암호화됨 (읽을 수 없다)</text>
|
||||
<text x="34" y="474" class="s" fill="#cf222e">→ 다른 것은 TTL 하나뿐이다</text>
|
||||
|
||||
<rect x="444" y="356" width="396" height="126" class="ok"/>
|
||||
<text x="458" y="378" class="tb">그래서 TTL 이 정리 규칙이 된다</text>
|
||||
<text x="458" y="398" class="s">--cookie-refresh 가 없어 TTL 이 갱신되지 않는다 (refresh:disabled)</text>
|
||||
<text x="458" y="416" class="s">→ TTL 은 생성 시각의 정확한 함수다</text>
|
||||
<rect x="460" y="424" width="364" height="26" class="box"/>
|
||||
<text x="470" y="442" class="t">생성시각 = 지금 − (cookie-expire − TTL)</text>
|
||||
<text x="458" y="466" class="s" fill="#1a7f37">이 값이 회전 시각보다 이르면 고아. 검증: 역산 11:30:26 vs 로그 11:30:27 — 1초 오차</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,57 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 430" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,sans-serif">
|
||||
<style>
|
||||
.box{fill:#fff;stroke:#8c959f;stroke-width:1.4;rx:6}
|
||||
.dead{fill:#fff5f5;stroke:#cf222e;stroke-width:1.6;stroke-dasharray:5 3;rx:6}
|
||||
.ok{fill:#f6fdf6;stroke:#1a7f37;stroke-width:1.6;rx:6}
|
||||
.warn{fill:#fff8f0;stroke:#bf8700;stroke-width:1.5;rx:6}
|
||||
.t{font-size:12px;fill:#1f2328}
|
||||
.tb{font-size:12.5px;fill:#1f2328;font-weight:600}
|
||||
.s{font-size:10.5px;fill:#656d76}
|
||||
.ttl{font-size:14px;fill:#1f2328;font-weight:600}
|
||||
.r{stroke:#cf222e;stroke-width:1.6;fill:none}
|
||||
.g{stroke:#1a7f37;stroke-width:1.6;fill:none}
|
||||
.k{stroke:#8c959f;stroke-width:1.3;fill:none}
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#8c959f"/></marker>
|
||||
<marker id="ar" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#cf222e"/></marker>
|
||||
<marker id="ag" markerWidth="8" markerHeight="8" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 z" fill="#1a7f37"/></marker>
|
||||
</defs>
|
||||
<text x="20" y="26" class="ttl">D-4a — deploy 훅 하나로 38분 25초가 1~2초가 된다</text>
|
||||
<text x="20" y="44" class="s">시각은 전부 실제 UTC (test-server 시계에서 106초 보정)</text>
|
||||
|
||||
<rect x="20" y="68" width="820" height="112" class="dead"/>
|
||||
<text x="34" y="90" class="tb">D-4 — 훅이 없을 때</text>
|
||||
<line x1="60" y1="130" x2="800" y2="130" class="k"/>
|
||||
<line x1="90" y1="120" x2="90" y2="140" stroke="#cf222e" stroke-width="2"/>
|
||||
<line x1="740" y1="120" x2="740" y2="140" stroke="#1a7f37" stroke-width="2"/>
|
||||
<rect x="90" y="122" width="650" height="16" class="dead"/>
|
||||
<text x="415" y="134" class="s" text-anchor="middle" fill="#cf222e">옛 인증서를 계속 서빙 — 428회 관측</text>
|
||||
<text x="62" y="158" class="s">08:20:27 디스크 기록</text>
|
||||
<text x="660" y="158" class="s">08:58:52 사람이 nginx -s reload</text>
|
||||
<text x="415" y="112" class="tb" text-anchor="middle" fill="#cf222e">2305초 = 38분 25초</text>
|
||||
<text x="34" y="174" class="s">아무도 reload 하지 않았다면 다음 nginx 재시작까지 = 사실상 무기한</text>
|
||||
|
||||
<rect x="20" y="196" width="820" height="112" class="ok"/>
|
||||
<text x="34" y="218" class="tb">D-4a — deploy 훅을 넣었을 때</text>
|
||||
<line x1="60" y1="258" x2="800" y2="258" class="k"/>
|
||||
<line x1="90" y1="248" x2="90" y2="268" stroke="#1a7f37" stroke-width="2"/>
|
||||
<line x1="104" y1="248" x2="104" y2="268" stroke="#1a7f37" stroke-width="2"/>
|
||||
<rect x="90" y="250" width="14" height="16" class="ok"/>
|
||||
<text x="62" y="286" class="s">12:27:49.05 발급 (SCT — CT 로그의 독립 시계)</text>
|
||||
<text x="360" y="286" class="s">12:27:50 nginx -t · 새 워커 37252 · 12:27:51 reload</text>
|
||||
<text x="150" y="244" class="tb" fill="#1a7f37">1~2초, 자동</text>
|
||||
<text x="34" y="302" class="s">certbot 이 파일을 쓴 직후 같은 실행 안에서 deploy 훅을 부른다 — 사람이 개입할 자리가 없다</text>
|
||||
|
||||
<rect x="20" y="324" width="400" height="92" class="box"/>
|
||||
<text x="34" y="346" class="tb">판정은 문구가 아니라 워커 PID 로</text>
|
||||
<text x="34" y="366" class="s">master 585 → 585 (유지)</text>
|
||||
<text x="34" y="384" class="s">worker 28829 → 37252 (교체 = reload 됨)</text>
|
||||
<text x="34" y="404" class="s">nginx 는 인증서를 기동 시 읽어 메모리에 든다</text>
|
||||
|
||||
<rect x="444" y="324" width="396" height="92" class="warn"/>
|
||||
<text x="458" y="346" class="tb">★ 함정 — 성공을 실패로 오독한다</text>
|
||||
<text x="458" y="366" class="s">Hook 'deploy-hook' ran with error output:</text>
|
||||
<text x="458" y="384" class="s"> [warn] could not build optimal types_hash …</text>
|
||||
<text x="458" y="402" class="s">nginx 경고가 stderr 로 나갔을 뿐. 내용은 test is successful</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -9,6 +9,14 @@ A-7 이 **가설로 남긴 것**을 확정하는 실험이다. 확정해 보니
|
||||
|
||||
---
|
||||
|
||||
## 구조
|
||||
|
||||

|
||||
|
||||
> 다이어그램 규약은 [`diagrams/_style.md`](diagrams/_style.md).
|
||||
|
||||
---
|
||||
|
||||
## 0. 결론부터
|
||||
|
||||
| 확인 | 결과 |
|
||||
|
||||
@@ -9,6 +9,14 @@ B-7 이 **「★ 지우지 못했다」** 로 남긴 자리를 잰다.
|
||||
|
||||
---
|
||||
|
||||
## 구조
|
||||
|
||||

|
||||
|
||||
> 다이어그램 규약은 [`diagrams/_style.md`](diagrams/_style.md).
|
||||
|
||||
---
|
||||
|
||||
## 0. 결론부터
|
||||
|
||||
| 물음 | 답 |
|
||||
|
||||
@@ -10,6 +10,14 @@ D-4 는 결함을 찾고 **처방을 적어두고 검증하지 않았다.**
|
||||
|
||||
---
|
||||
|
||||
## 구조
|
||||
|
||||

|
||||
|
||||
> 다이어그램 규약은 [`diagrams/_style.md`](diagrams/_style.md).
|
||||
|
||||
---
|
||||
|
||||
## 0. 결론부터
|
||||
|
||||
| 확인 | 결과 |
|
||||
|
||||
Reference in New Issue
Block a user