Reviewer 결과 17 PASS / 1 REJECT (#267 admin 권한 critical). - 17개 설계서를 Draft → Approved로 갱신 - #267(backend-user)은 critical 결함으로 06-Reviewer 유지 - 후속 17개 개선 이슈(#289~#305) 자동 등록 — 결함 124건 백로그 반영 (critical 3 / major 46 / minor 75) - docs/README.md에 18개 설계서 인덱스 추가 - CHANGELOG.md 2026-06-15 섹션 추가 Refs: #266 #268-#283 (현행화 완료) #267 (대기) #289-#305 (백로그)
6.9 KiB
6.9 KiB
설계서: 백엔드 - Health/모니터링 (#277)
상태: Approved 작성: [AI] Architect · 최종수정: 2026-06-15 추적성 — Redmine: #277 · 관련 ADR: 없음 · 구현 파일:
backend-java/src/main/java/com/tasteby/controller/HealthController.java· 테스트: TBD (현재 없음)
1. 목적 (Why)
PM2(dev) / Kubernetes (OKE prod) / Nginx Ingress 가 백엔드 프로세스가 살아있는지 판단할 수 있는 경량 HTTP 엔드포인트를 제공해, 장애 시 재기동·트래픽 차단을 자동화한다.
2. 범위 (Scope)
- 포함:
GET /api/health— 항상200 OK와{"status":"ok"}를 반환하는 liveness 체크 엔드포인트.- 인증 없이 호출 가능(공개).
- 제외 (out of scope):
- DB/Redis/외부 API 의존성 상태를 포함하는 deep health(readiness) 체크.
- Spring Boot Actuator (
/actuator/health) 활성화. - 메트릭(Micrometer/Prometheus) 노출.
- 분산 트레이싱·로그 수집.
- 알림(Slack/Email/PagerDuty) 통합.
3. 인수조건 (Acceptance Criteria)
GET /api/health호출 시 HTTP 200 과 본문{"status":"ok"}를 반환한다.- 인증 없이 누구나 호출 가능하다(
WebConfigCORS 허용 범위 내). - 응답 본문은
Content-Type: application/json으로 직렬화된다(Spring 기본). - 외부 의존성(DB/Redis/LLM)이 다운되어도 본 엔드포인트는 영향을 받지 않는다(순수 인메모리 응답).
4. 컨텍스트 & 제약
- 의존성:
- Spring Web (
@RestController,@GetMapping). - 외부 의존성 없음 — 컨트롤러 자체가 무상태 상수 응답.
- 호출자: PM2 헬스(현재는 미사용), Kubernetes liveness/readiness probe(향후), Nginx upstream check(현재는 미사용), Uptime 모니터링.
- Spring Web (
- 제약:
- 응답 시간 < 50ms 가정. 어떤 비용 있는 작업도 포함하지 않아야 함.
- 본 엔드포인트가 200 을 반환한다고 해서 "서비스 정상" 을 의미하지 않음(프로세스 생존만 보장).
- 가정:
- 프로세스가 응답할 수 있으면 JVM/Tomcat 이 살아있다는 신호로 충분.
- 인증 미들웨어(Spring Security/필터)는
/api/health를 통과시킨다(현재 인증 강제 없음).
5. 아키텍처 개요
- 모듈:
HealthController— 단일@RestController클래스, 메서드 1개.
- 경계:
- I/O: HTTP 입출력만. DB/Redis/LLM 호출 없음.
- 순수 로직: 상수
Map반환 — 테스트 자체가 거의 불필요한 수준.
Probe/Monitor ──HTTP GET /api/health──▶ Spring DispatcherServlet
│
▼
HealthController.health()
│
▼
Map.of("status","ok") → JSON 200
6. 데이터 모델
- 단순 응답 객체:
Map<String, String>의 불변 단일 엔트리.
{ "status": "ok" }
- 입력 파라미터/바디 없음.
- 상태 코드: 항상 200. 다른 코드 없음.
- 경계 검증: 해당 없음.
7. 함수 명세 (Function Specs)
| 함수 | 책임(1줄) | 시그니처(잠정) | 입력 | 출력 | 에러/실패 | 복잡? |
|---|---|---|---|---|---|---|
HealthController.health |
liveness 응답 반환 | Map<String,String> health() |
없음 | {"status":"ok"} |
이론상 없음(JVM/Tomcat 죽으면 연결 실패) | 단순 |
8. 흐름 / 알고리즘
- 클라이언트(K8s probe / 모니터)가
GET /api/health호출. - Spring DispatcherServlet 라우팅 →
HealthController.health()호출. - 메서드는
Map.of("status","ok")상수 반환. - Jackson 이 JSON 직렬화 → HTTP 200 응답.
cron 표현/주기: 본 컨트롤러 자체는 스케줄러가 아님(외부 probe 가 주기적으로 호출). 운영 권장 주기: K8s liveness 10s, readiness 5s.
9. 엣지케이스 & 에러 처리
- JVM 데드락/OOM: 응답 없음 → probe 가 타임아웃 → 비정상 판정 → 재기동(외부 메커니즘이 처리, 본 엔드포인트가 의도한 시나리오).
- 요청 폭주(DDoS): 본 메서드는 매우 가볍지만 인증/레이트리밋이 없음. Nginx Ingress 단에서 처리 가정.
- DB/Redis 다운: 본 엔드포인트는 영향 없음(의도된 동작). 단, 운영자가 "서비스 정상"으로 오인할 수 있는 한계 — 별도 readiness 필요(11장 참조).
- 잘못된 HTTP 메서드:
POST /api/health등은 405 (Spring 기본). - CORS:
WebConfig의 허용 origin 에 따라 브라우저 접근 제한될 수 있음(서버-서버 probe 에는 영향 없음).
10. 테스트 계획
현재 자동 테스트 없음(TBD). 권장 케이스:
- Unit/Slice (
@WebMvcTest(HealthController.class)):GET /api/health→ 200 + 본문{"status":"ok"}.POST /api/health→ 405.
- Smoke:
- 운영/dev 배포 후
curl -sf https://www.tasteby.net/api/health가 0 종료 코드.
- 운영/dev 배포 후
- 모킹: 불필요 — 의존성 없음.
11. 리스크 & 대안 검토
- 선택: 자체 컨트롤러 1개 + 상수 응답.
- 장점: 의존성 0, 인증/필터 우회 명확, K8s probe 와 1:1 매핑 쉬움.
- 단점: deep health(DB/Redis 연결 확인) 부재 → "프로세스는 살아있지만 서비스 불가" 상황 감지 못 함.
- 대안:
- Spring Boot Actuator (
/actuator/health) — DB/Redis HealthIndicator 자동 구성, 표준화. 보안 노출 범위 제어 필요. → readiness 용도로 향후 도입 후보. - K8s readinessProbe 별도 엔드포인트 (
/api/health/ready) — DB ping, Redis ping 결과 합산. 본 설계의 자연스러운 확장. - 외부 모니터링(UptimeRobot/Healthchecks.io) — HTTP 200 만으로 충분히 활용 가능.
- Spring Boot Actuator (
- 트레이드오프: 현재는 운영자 1인 / 트래픽 적음 → 최소 구현이 합리적. Prod 안정화 단계에서 Actuator + readiness 분리 권장.
- 되돌리기 어려운 결정 없음.
12. 미해결 질문 (Open Questions)
- DB/Redis 연결을 검사하는 readiness 엔드포인트(
/api/health/ready)를 언제 도입할 것인가? - Spring Boot Actuator 를 켜고 노출 범위(어떤 엔드포인트, 어떤 인증)를 어떻게 제어할 것인가?
- Prometheus 메트릭/Grafana 대시보드를 운영할 것인가(현재는 PM2/kubectl 로그 의존)?
- K8s probe 구성(initialDelay, periodSeconds, failureThreshold) 표준값은?
- 헬스 응답에 빌드 버전/커밋 SHA를 포함할 것인가(
/api/version분리 vs 통합)? - 본 엔드포인트도 인증/IP 제한 대상으로 둘 필요가 있는가(공개 권장)?