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>
137 lines
9.1 KiB
Markdown
137 lines
9.1 KiB
Markdown
---
|
|
kind: CASE
|
|
slug: a-startup-probe-that-never-runs
|
|
title: startup probe가 production에서 한 번도 실행되지 않는다
|
|
topic: redis-command-admission
|
|
project: clean-architecture-backend-template
|
|
status: 게시 전
|
|
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
rootTreeNode: case:a-startup-probe-that-never-runs
|
|
evidenceCapturedOn: 2026-09-02
|
|
assets:
|
|
- key: a-startup-probe-that-never-runs
|
|
file: ../../../final/evidence/rendered/a-startup-probe-that-never-runs.svg
|
|
evidence:
|
|
- ../../../final/evidence/raw/a-startup-probe-that-never-runs.txt
|
|
source:
|
|
- 분석 문서는 cache-redis 어댑터 편 §6 이다. 그 절이 탐침이 확인하는 넷을 나열하고, 넷째의 javadoc 을 인용하고, 두 탐침의 프로덕션 참조가 javadoc 링크 하나뿐이라는 것과 자동설정이 탐침을 부르지 않는다는 것을 기록한다. 판정은 P2 이고, 수정은 자동설정에 탐침을 실행하는 빈 하나를 더하는 것이다.
|
|
- 같은 사고의 더 상세한 기록은 저장소 문서 쪽에 있다. 지원 매트릭스가 승격과 강등 시각을 초 단위로 적고, 운영 문서와 런북이 가드를 적용한 뒤 같은 승격에서 무엇이 달라졌는지 적는다.
|
|
---
|
|
|
|
# startup probe가 production에서 한 번도 실행되지 않는다
|
|
|
|
기동 시 서버 능력을 확인하는 탐침이 있다. 그것을 만들거나 부르는 프로덕션 코드가 없어 한 번도 실행되지 않는다.
|
|
|
|
## 관계
|
|
|
|
- **@Bean이 있다는 것은 조립 증거가 아니다**
|
|
이 사례가 그 규칙의 형태다.
|
|
- **시작 검증기가 도는지는 그 능력에 자동설정 루트가 있는지와 일치한다**
|
|
시작 검증기가 도는지를 자동설정 루트로 확인하는 절차다.
|
|
- **하위 시스템 전체가 미배선인데 그것을 켜는 플래그는 시작 검사를 수행한다**
|
|
플래그와 실행의 어긋남이 반대 방향으로 나타난 사례다.
|
|
|
|
## 문제
|
|
|
|
기동 탐침은 서버가 실제로 무엇인지 묻는다. 그것이 확인하는 것은 넷이다. 서버 버전, 클러스터와 데이터베이스 번호, 명시적으로 켠 능력의 실재, 그리고 복제 배포의 쓰기 내구성이다.
|
|
|
|
넷째의 javadoc 이 이 저장소의 실측 사고 기록을 숫자째로 담고 있다.
|
|
|
|
## 결론
|
|
|
|
그 기동 실패는 일어나지 않는다.
|
|
|
|
두 탐침 클래스를 언급하는 프로덕션 코드는 다른 설정 클래스의 javadoc 링크 하나뿐이고, 확인 메서드를 부르는 프로덕션 코드는 0 이다. 자동설정이 만드는 빈 일곱에 탐침은 없다.
|
|
|
|
로직은 완성되어 있고 테스트 열여덟 케이스가 네 규칙을 고정한다. 없는 것은 호출 지점 하나다.
|
|
|
|
## 검증 환경
|
|
|
|
OpenJDK : 21.0.12
|
|
확인 방식 : 정적 도달성 확인
|
|
소스 수정 : x
|
|
|
|
## 재현 조건
|
|
|
|
1. 기동 탐침의 클래스 javadoc 과 확인 메서드 본문을 읽고, 무엇을 몇 가지 확인하는지 센다.
|
|
2. 넷째 항목의 javadoc 에 적힌 사고 기록과 결론, 그리고 검사가 두 겹인 이유를 읽는다.
|
|
3. 두 탐침 클래스를 언급하는 프로덕션 코드를 세고 그것이 무엇인지 확인한다.
|
|
4. 확인 메서드를 부르는 프로덕션 코드를 센다.
|
|
5. 자동설정이 만드는 빈을 나열하고 그중 탐침이 있는지 센다.
|
|
6. 두 테스트 파일의 케이스 수를 센다.
|
|
|
|
## 본문
|
|
|
|
<!-- body:start -->
|
|
|
|
기동 탐침은 서버가 실제로 무엇인지 한 번, 기동 시에 묻는다.
|
|
|
|
이 탐침이 무엇을 막는지부터 본다. 그것이 실행되지 않는다는 판정이 무엇을 잃는 것인지가 거기서 정해진다.
|
|
|
|
## 확인하는 것은 넷이다
|
|
|
|
:::evidence key="a-startup-probe-that-never-runs" alt="코드베이스에서 기동 탐침이 자기를 소개하는 문단과 확인 메서드 본문이 부르는 두 검사, 넷째 항목의 javadoc 이 담은 실측과 결론과 검사가 두 겹인 이유, 두 탐침을 언급하는 프로덕션 코드 하나와 그것이 javadoc 링크라는 것과 확인 메서드를 부르는 코드 수, 자동설정이 만드는 빈 일곱과 그중 탐침의 수, 그리고 로직을 고정하는 테스트 케이스 수를 뽑은 출력 70줄. 탐침을 부르는 프로덕션 코드가 0 이고 자동설정의 빈 일곱에 탐침이 없다는 것이 그 출력에 보인다." caption="탐침의 소개 문단과 두 검사 · 넷째의 실측과 두 겹 검사 · 언급 1(javadoc 링크) · 호출 0 · 빈 일곱에 탐침 없음 · 테스트 18케이스 — 70줄" zoom="true"
|
|
:::
|
|
|
|
확인 메서드가 두 호출로 넷을 덮는다. 앞의 호출이 서버 버전과 배포 모드와 데이터베이스 번호와 명령 목록으로 능력을 판정하고, 뒤의 호출이 복제 배포의 쓰기 내구성을 요구한다.
|
|
|
|
클래스 javadoc 이 왜 서버에 묻는지 적는다. 설정은 배포가 무엇을 의도하는지 말하고 서버만이 무엇이 참인지 말한다는 것, 관리형 Redis 가 광고하는 버전이 모듈의 존재를 뜻하지 않는다는 것, 그리고 복제 배포의 쓰기 내구성은 어떤 클라이언트도 보상할 수 없는 서버 설정이라는 것이다.
|
|
|
|
같은 문단이 시점의 값도 적는다. 빠진 능력을 첫 요청에서 발견하면 장애이고, 여기서 발견하면 실패한 배포다.
|
|
|
|
## 넷째 항목의 javadoc 은 실측을 숫자째로 담는다
|
|
|
|
그 javadoc 은 이것이 SDK 가 보상할 수 없는 유일한 서버 설정이라고 적는다.
|
|
|
|
승격으로 밀려난 주 노드는 그 사실을 즉시 알지 못한다. 아는 순간까지 쓰기에 계속 성공을 답하고, 새 주 노드에서 재동기화할 때 그 쓰기들이 버려진다.
|
|
|
|
센티널 레인이 그것을 쟀다. 11초 동안 2,086건이 승인된 뒤 폐기됐고, 같은 실행에서 호출자에게 실패로 보인 명령은 통틀어 하나뿐이었다.
|
|
|
|
그 아래 문장이 왜 아무도 못 보는지 적는다. 서버가 답했으므로 드라이버도, 이 SDK 도, 호출자도 전부 성공으로 기록한다. 더할 지표도, 재시도할 실패도, 그것을 서술할 확신 값도 없다.
|
|
|
|
## 그래서 경고가 아니라 기동 실패다
|
|
|
|
복제 최소 개수와 상한이 걸린 최대 지연이 그 상황을 호출자가 대응할 수 있는 거절로 바꾼다. 같은 승격이 그때는 2,086건 대신 한 건을 잃었다.
|
|
|
|
그래서 그 설정 없는 복제 배포는 경고가 아니라 기동 실패라고 적는다. 보증을 무의미하게 만드는 설정은 조용히 성능을 낮추는 대신 컨텍스트를 멈춘다는 것이 이 SDK 의 원칙이라는 것이다.
|
|
|
|
면제는 가능하다. 배포가 정말로 쓰기 하나를 잃어도 괜찮을 수 있고 이 SDK 가 서버를 소유하지 않기 때문이다. 다만 면제에는 명시적 설정이 필요해서, 그 거래가 사고 중에 발견되는 대신 기록으로 남는다.
|
|
|
|
## 그 검사 자체도 한 번 고쳐졌다
|
|
|
|
같은 javadoc 이 검사가 두 겹인 이유를 적는다.
|
|
|
|
복제 개수만으로는 몇 개가 연결되어 있어야 하는지만 정해진다. 얼마나 뒤처져도 되는지는 최대 지연이 정하고, Redis 는 그 값 0 을 지연 요구 없음으로 다룬다.
|
|
|
|
그래서 복제 둘을 요구하면서 지연 상한을 0 으로 둔 배포는, 임의로 뒤처진 복제 둘이 붙어 있기만 하면 쓰기를 받는다. 개수 요구가 없애려던 바로 그 노출이 그대로 남는다.
|
|
|
|
개수만 검사하던 동안 그 설정이 통과했다. 그러면서 실패 메시지는 운영자에게 지연 상한을 설정하라고 말하고 있었다.
|
|
|
|
## 그 기동 실패는 일어나지 않는다
|
|
|
|
두 탐침 클래스를 언급하는 프로덕션 코드가 하나뿐이다. 그것도 다른 설정 클래스의 javadoc 안에 있는 링크다.
|
|
|
|
확인 메서드를 부르는 프로덕션 코드는 0 이다.
|
|
|
|
자동설정은 빈 일곱을 만든다. 설정과 그 검증, 자격증명, 런타임 클라이언트와 소유자, 그리고 헬스 지표 둘이다. 그중 탐침은 0 이다.
|
|
|
|
## 없는 것은 호출 지점 하나다
|
|
|
|
로직은 완성되어 있다. 두 테스트 파일의 열여덟 케이스가 네 규칙을 고정한다.
|
|
|
|
탐침이 연결을 들고 있지 않은 것은 설계된 것이다. 서버 사실을 인자로 받아서, 같은 로직을 단위 테스트와 실제 레인이 함께 쓰고 어느 계정이 물을지를 호출자가 정한다.
|
|
|
|
그 사실 중 둘을 읽는 명령이 관리 평면이라 애플리케이션 계정은 거부된다. 그래서 조립은 관리 계정이 설정된 배포에서만 완전하다.
|
|
|
|
## 지금 남은 것은 장애 쪽이다
|
|
|
|
빠진 능력을 첫 요청에서 발견하면 장애이고 여기서 발견하면 실패한 배포다. 조립이 없으므로 남은 것은 앞쪽이다.
|
|
|
|
복제 내구성은 그마저도 아니다. 서버가 성공을 답하므로 장애로도 나타나지 않는다.
|
|
|
|
## 확인하지 못한 것
|
|
|
|
애플리케이션을 부팅해 탐침이 실행되지 않는 것을 관측하지 않았다. 정적으로 도달성만 확인했고, 위 실측값은 이 저장소의 센티널 레인이 잰 것을 javadoc 에서 인용한 것이지 이 기록을 위해 다시 잰 것이 아니다.
|
|
|
|
<!-- body:end -->
|