살아 있는지와 트래픽을 받을 수 있는지는 다른 질문이다.
얕은 헬스체크 프로세스가 살아 있는지만 확인 (200 을 그냥 반환)
장점 의존 자원 장애가 전체 인스턴스를 죽이지 않는다
단점 DB 가 죽어도 '정상' 으로 보인다
깊은 헬스체크 DB·캐시 연결까지 확인
장점 진짜 서비스 가능 여부를 반영한다
단점 DB 가 잠깐 흔들리면 '모든' 인스턴스가 동시에 제외된다
→ 트래픽 받을 곳이 사라져 장애가 증폭된다
깊게 만들어 전멸하는 사고
DB 순단 3초
- 모든 파드의 깊은 헬스체크가 동시에 실패
- 전부 NotReady → 트래픽 받을 곳이 없다 (503)
- DB 가 복구돼도 파드가 한꺼번에 다시 붙어 DB 를 또 무너뜨린다
원래 3초 순단이었을 일이 수 분짜리 장애가 된다
실무 기본형
liveness 얕게 자기 자신의 문제만 본다 (데드락 · 무한 루프)
실패하면 '재시작' 이 답인 경우만 넣는다
readiness 중간 트래픽 수용 판단. 필수 의존만, 선택 의존은 제외한다
깊은 점검 별도 엔드포인트로 두고 모니터링만 시킨다
→ 알림은 오되 트래픽 판정에는 쓰지 않는다
liveness 에 DB 확인을 넣으면 안 되는 이유
- DB 장애로 파드가 재시작된다 → 재시작해도 DB 는 여전히 죽어 있다
- 무한 재시작 루프(CrashLoopBackOff)
- 로그도 남지 않고 상황만 악화된다
엔드포인트 설계
location = /healthz {
access_log off;
return 200 "ok\n";
}
- '=' 로 정확히 매칭해 매칭 비용을 줄인다
- access_log off — 헬스체크가 로그의 대부분을 차지하는 것을 막는다
- 인증을 걸지 않는다 (LB 가 못 부른다)
- 대신 내부 대역에서만 접근 가능하게 하거나 경로를 추측하기 어렵게 한다
- 응답이 가벼워야 한다 — 헬스체크가 부하가 되면 본말전도다
주기와 임계값
- 주기가 짧고 임계가 낮으면 — 순간 지연에도 제외된다 (불안정)
- 주기가 길고 임계가 높으면 — 죽은 서버로 오래 보낸다 (장애 지속)
둘의 곱이 '장애 감지까지 걸리는 시간' 이고, 그 값이 무중단 배포의 대기 시간을 결정한다
- 두 설정은 따로 정하는 것이 아니라 함께 정한다
의존이 흔들릴 때의 정책
- 필수 의존(없으면 아무것도 못 함) — readiness 에 넣는다
- 선택 의존(없어도 일부는 됨) — 넣지 않는다. 기능 축소로 대응한다
예 — 추천 서비스가 죽었다
- 넣으면 전체 인스턴스가 트래픽에서 빠진다 → 서비스 전체 중단
- 안 넣으면 추천 영역만 비어 나간다 → 나머지는 정상
가용성 설계의 핵심 판단이 이 한 줄에 들어 있다
종속 관계가 순환하지 않게
A 의 헬스체크가 B 를 호출하고, B 의 헬스체크가 A 를 호출하면 한쪽이 흔들릴 때 둘 다 NotReady 가 된다
헬스체크는 '자기 자신' 을 보는 것이 원칙이다 다른 서비스의 상태는 서킷 브레이커와 폴백으로 다룬다
시작 지연이 긴 경우
기동에 오래 걸리는 애플리케이션은 liveness 가 먼저 실패해 '기동 중에 재시작' 되는 루프에 빠질 수 있다
- 시작 전용 프로브(startup probe)를 두거나
- liveness 의 초기 지연을 충분히 준다
면접 함정
- ❌ "헬스체크는 깊을수록 정확하다" → 공통 의존이 흔들리면 동시에 전멸한다.
- ❌ "liveness와 readiness는 이름만 다르다" → 실패 시 조치가 재시작이냐 트래픽 제외냐로 완전히 다르다.