The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4.6 KiB
4.6 KiB
id, kind, slug, title, topic, topicName, project, status, studio, questionStatus
| id | kind | slug | title | topic | topicName | project | status | studio | questionStatus |
|---|---|---|---|---|---|---|---|---|---|
| 5088ce14-b096-41d3-abba-64b7afb48bb9 | QUESTION | promote-feed-visible-to-cqrs | feed_visible을 Production CQRS로 승격할 것인가 | jpa-feed-query-performance | JPA 피드 조회 성능 | Liner N + 1문제 | 게시 전 | https://hyeonworks.com/studio/documents/5088ce14-b096-41d3-abba-64b7afb48bb9/edit | OPEN |
feed_visible을 Production CQRS로 승격할 것인가
사용자별 가시성을 미리 계산한 테이블은 조회를 커버링 인덱스 하나로 만들었다. 상시 유지하려면 원본 변경을 투영에 동기화해야 하고, 이는 별도 물리 읽기 저장소를 두는 결정이 된다.
관계
- Feed Visibility Query Pattern 세 방식을 비교한 기준이다.
- 현재 Read Model은 CQRS-lite로 유지한다 지금 유지하기로 한 범위다.
- Visibility OR이 Keyset Index를 깨뜨린 문제 사전계산이 풀려던 문제다.
사실
- 사전계산 조회는 커버링 인덱스의 단일 스캔이었다. OR도 조인도 정렬도 없었다.
- 단일 OR은 후보 1,500을 훑고 상위 20을 정렬로 만들었다. UNION 분해는 분기별로 스캔했다.
- 세 방식은 같은 조회 사용자에게 같은 항목 집합을 반환했다.
- 통합 쿼리에서 부모 선택을 사전계산으로 두면 깊은 페이지에서 인덱스 범위로 19행만 읽었다. 단일 OR로 두면 가시성 분기와 멘션 조건을 다시 계산하며 200행을 읽었다.
- 현재 구현은 사전계산 테이블을 테스트 안에서 만들고 지운다. 상시 유지하지 않는다.
- 현재 읽기 경로는 쓰기와 같은 저장소 위에 읽기 전용 포트·DTO·쿼리만 분리한 형태다.
가정
- 고트래픽 읽기에서는 조회 비용 차이가 실제 부하로 나타난다.
- 상시 유지하면 원본 변경마다 투영 갱신이 필요하다.
- 투영이 어긋나면 사용자가 볼 수 없는 항목을 보거나 볼 수 있는 항목을 놓친다.
미지수
- 현재 트래픽에서 단일 OR이나 UNION 분해로 충분한가. 사전계산이 필요한 임계가 어디인가.
- 동기화를 어떤 방식으로 하는가. 도메인 이벤트인가 아웃박스인가.
- 투영 갱신이 늦어졌을 때 허용 가능한 지연은 얼마인가.
- 가시성이 바뀌는 사건이 무엇인가. 아이템 공개 범위 변경, 멘션 추가·삭제, 사용자 삭제까지 포함하는가.
- 사용자 수만큼 늘어나는 저장 공간이 감당 가능한가.
- 투영이 어긋났을 때 어떻게 발견하고 복구하는가.
- 이 변경이 현재 정한 계약의 범위를 넘는가. 넘는다면 계약과 가드레일을 어떻게 개정하는가.
제약
- 현재 계약에서 별도 물리 읽기 저장소는 에스컬레이션 대상으로 남겨 두었다. 승격하려면 계약을 먼저 개정해야 한다.
- 가시성은 보안에 걸린 조건이다. 투영이 어긋나면 노출 사고가 된다. 지연 허용치를 느슨하게 잡을 수 없다.
- 지금까지의 측정은 단일 스레드 로컬 값이다. 고트래픽에서 어느 방식이 필요한지는 이 측정으로 답할 수 없다.
선택지
1. 현재 범위를 유지하고 요청 시 조회로 푼다
단일 OR이나 UNION 분해로 조회한다. 동기화 비용이 없고 정합성 문제도 없다.
고트래픽에서 조회 비용이 그대로 남는다.
2. 사전계산을 상시 유지하는 읽기 저장소로 승격한다
쓰기 변경을 투영에 반영하고 조회는 투영만 읽는다. 조회 비용이 가장 낮다.
동기화 경로, 지연 허용치, 정합성 검증, 복구 절차를 모두 설계해야 한다. 계약 개정도 필요하다.
3. 일부만 사전계산한다
접근이 잦은 구간만 투영으로 유지하고 나머지는 요청 시 조회한다.
두 경로를 함께 운영해야 하고 어느 구간을 투영에 둘지 정하는 기준이 필요하다.
다음 검증
-
부하 테스트로 현재 조회 방식이 목표 트래픽을 견디는지 확인한다. 이 판단은 단일 스레드 측정으로 대신할 수 없다.
-
가시성이 바뀌는 사건을 모두 열거하고 각각이 투영의 어느 행에 영향을 주는지 정리한다.
-
사용자 수와 아이템 수를 곱한 투영 크기를 계산한다.
-
동기화 지연의 허용치를 정한다. 가시성은 보안 조건이므로 이 값이 설계를 좌우한다.
-
투영과 원본이 어긋났는지 확인하는 방법과 복구 절차를 정의한다.
-
위 결과를 보고 계약을 개정할지 판단한다.