9.0 KiB
kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source
| kind | slug | title | topic | project | status | sourceRevision | rootTreeNode | evidenceCapturedOn | assets | evidence | source | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CASE | a-startup-probe-that-never-runs | startup probe가 production에서 한 번도 실행되지 않는다 | redis-command-admission | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | case:a-startup-probe-that-never-runs | 2026-09-02 |
|
|
|
startup probe가 production에서 한 번도 실행되지 않는다
기동 시 서버 능력을 확인하는 탐침이 있다. 그것을 만들거나 부르는 프로덕션 코드가 없어 한 번도 실행되지 않는다.
관계
- @Bean이 있다는 것은 조립 증거가 아니다 이 사례가 그 규칙의 형태다.
- 시작 검증기가 도는지는 그 능력에 자동설정 루트가 있는지와 일치한다 시작 검증기가 도는지를 자동설정 루트로 확인하는 절차다.
- 하위 시스템 전체가 미배선인데 그것을 켜는 플래그는 시작 검사를 수행한다 Redis에서는 설정이 보증을 요구하지만 startup probe가 자동설정 경로에 연결되지 않아 실행되지 않았다.
문제
기동 탐침은 서버가 실제로 무엇인지 묻는다. 그것이 확인하는 것은 넷이다. 서버 버전, 클러스터와 데이터베이스 번호, 명시적으로 켠 능력의 실재, 그리고 복제 배포의 쓰기 내구성이다.
넷째의 javadoc 이 이 저장소의 실측 사고 기록을 숫자째로 담고 있다.
결론
그 기동 실패는 일어나지 않는다.
두 탐침 클래스를 언급하는 프로덕션 코드는 다른 설정 클래스의 javadoc 링크 하나뿐이고, 확인 메서드를 부르는 프로덕션 코드는 0 이다. 자동설정이 만드는 빈 일곱에 탐침은 없다.
로직은 완성되어 있고 테스트 열여덟 케이스가 네 규칙을 고정한다. 없는 것은 호출 지점 하나다.
검증 환경
OpenJDK : 21.0.12 확인 방식 : 정적 도달성 확인 소스 수정 : x
재현 조건
- 기동 탐침의 클래스 javadoc 과 확인 메서드 본문을 읽고, 무엇을 몇 가지 확인하는지 센다.
- 넷째 항목의 javadoc 에 적힌 사고 기록과 결론, 그리고 검사가 두 겹인 이유를 읽는다.
- 두 탐침 클래스를 언급하는 프로덕션 코드를 세고 그것이 무엇인지 확인한다.
- 확인 메서드를 부르는 프로덕션 코드를 센다.
- 자동설정이 만드는 빈을 나열하고 그중 탐침이 있는지 센다.
- 두 테스트 파일의 케이스 수를 센다.
본문
기동 탐침은 서버가 실제로 무엇인지 한 번, 기동 시에 묻는다.
이 탐침이 무엇을 막는지부터 본다. 그것이 실행되지 않는다는 판정이 무엇을 잃는 것인지가 거기서 정해진다.
확인하는 것은 넷이다
:::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건 대신 한 건을 잃었다.
javadoc은 요구한 복제 보증을 무효화하는 서버 설정이 확인되면 경고만 남기지 않고 기동을 거부하도록 설계했다고 적는다.
면제는 가능하다. 배포가 정말로 쓰기 하나를 잃어도 괜찮을 수 있고 이 SDK 가 서버를 소유하지 않기 때문이다. 다만 면제에는 명시적 설정이 필요해서, 그 거래가 사고 중에 발견되는 대신 기록으로 남는다.
그 검사 자체도 한 번 고쳐졌다
같은 javadoc 이 검사가 두 겹인 이유를 적는다.
복제 개수만으로는 몇 개가 연결되어 있어야 하는지만 정해진다. 얼마나 뒤처져도 되는지는 최대 지연이 정하고, Redis 는 그 값 0 을 지연 요구 없음으로 다룬다.
그래서 복제 둘을 요구하면서 지연 상한을 0으로 둔 배포는, 두 replica가 연결돼 있기만 하면 지연 정도와 무관하게 쓰기를 받을 수 있다. replica 개수만 검사해서는 뒤처진 replica를 허용하는 위험을 막지 못한다.
개수만 검사하던 동안 그 설정이 통과했다. 그러면서 실패 메시지는 운영자에게 지연 상한을 설정하라고 말하고 있었다.
그 기동 실패는 일어나지 않는다
두 탐침 클래스를 언급하는 프로덕션 코드가 하나뿐이다. 그것도 다른 설정 클래스의 javadoc 안에 있는 링크다.
확인 메서드를 부르는 프로덕션 코드는 0 이다.
자동설정은 빈 일곱을 만든다. 설정과 그 검증, 자격증명, 런타임 클라이언트와 소유자, 그리고 헬스 지표 둘이다. 그중 탐침은 0 이다.
없는 것은 호출 지점 하나다
로직은 완성되어 있다. 두 테스트 파일의 열여덟 케이스가 네 규칙을 고정한다.
탐침이 연결을 들고 있지 않은 것은 설계된 것이다. 서버 사실을 인자로 받아서, 같은 로직을 단위 테스트와 실제 레인이 함께 쓰고 어느 계정이 물을지를 호출자가 정한다.
그 사실 중 둘을 읽는 명령이 관리 평면이라 애플리케이션 계정은 거부된다. 그래서 조립은 관리 계정이 설정된 배포에서만 완전하다.
지금 남은 것은 장애 쪽이다
빠진 능력을 첫 요청에서 발견하면 장애이고 여기서 발견하면 실패한 배포다. 조립이 없으므로 남은 것은 앞쪽이다.
복제 내구성은 그마저도 아니다. 서버가 성공을 답하므로 장애로도 나타나지 않는다.
확인하지 못한 것
애플리케이션을 부팅해 탐침이 실행되지 않는 것을 관측하지 않았다. 정적으로 도달성만 확인했고, 위 실측값은 이 저장소의 센티널 레인이 잰 것을 javadoc 에서 인용한 것이지 이 기록을 위해 다시 잰 것이 아니다.