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 (백로그)
119 lines
6.9 KiB
Markdown
119 lines
6.9 KiB
Markdown
<!-- 기능 설계서 — 백엔드 Health/모니터링.
|
|
작성: [AI] Architect. 빈 섹션 금지 — 해당 없으면 "해당 없음" 명시. -->
|
|
|
|
# 설계서: 백엔드 - Health/모니터링 (#277)
|
|
|
|
> **상태**: Approved <!-- Draft | Approved | Superseded -->
|
|
> **작성**: [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)
|
|
- [x] `GET /api/health` 호출 시 HTTP 200 과 본문 `{"status":"ok"}` 를 반환한다.
|
|
- [x] 인증 없이 누구나 호출 가능하다(`WebConfig` CORS 허용 범위 내).
|
|
- [x] 응답 본문은 `Content-Type: application/json` 으로 직렬화된다(Spring 기본).
|
|
- [x] 외부 의존성(DB/Redis/LLM)이 다운되어도 본 엔드포인트는 영향을 받지 않는다(순수 인메모리 응답).
|
|
|
|
## 4. 컨텍스트 & 제약
|
|
- **의존성**:
|
|
- Spring Web (`@RestController`, `@GetMapping`).
|
|
- 외부 의존성 없음 — 컨트롤러 자체가 무상태 상수 응답.
|
|
- 호출자: PM2 헬스(현재는 미사용), Kubernetes liveness/readiness probe(향후), Nginx upstream check(현재는 미사용), Uptime 모니터링.
|
|
- **제약**:
|
|
- 응답 시간 < 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>` 의 불변 단일 엔트리.
|
|
|
|
```json
|
|
{ "status": "ok" }
|
|
```
|
|
|
|
- 입력 파라미터/바디 없음.
|
|
- 상태 코드: 항상 200. 다른 코드 없음.
|
|
- 경계 검증: 해당 없음.
|
|
|
|
## 7. 함수 명세 (Function Specs)
|
|
|
|
| 함수 | 책임(1줄) | 시그니처(잠정) | 입력 | 출력 | 에러/실패 | 복잡? |
|
|
|------|-----------|----------------|------|------|-----------|-------|
|
|
| `HealthController.health` | liveness 응답 반환 | `Map<String,String> health()` | 없음 | `{"status":"ok"}` | 이론상 없음(JVM/Tomcat 죽으면 연결 실패) | 단순 |
|
|
|
|
## 8. 흐름 / 알고리즘
|
|
1. 클라이언트(K8s probe / 모니터)가 `GET /api/health` 호출.
|
|
2. Spring DispatcherServlet 라우팅 → `HealthController.health()` 호출.
|
|
3. 메서드는 `Map.of("status","ok")` 상수 반환.
|
|
4. 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 종료 코드.
|
|
- **모킹**: 불필요 — 의존성 없음.
|
|
|
|
## 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 만으로 충분히 활용 가능.
|
|
- **트레이드오프**: 현재는 운영자 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 제한 대상으로 둘 필요가 있는가(공개 권장)?
|