이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- liveness, readiness, startup probe는 각각 어떤 실패를 다루는가?
- resource request와 limit은 Spring JVM 운영에 어떤 영향을 주는가?
- probe와 limit을 잘못 잡으면 어떤 장애가 발생하는가?
개요
Probe와 resource 설정은 Kubernetes에서 Spring 애플리케이션의 생존, 트래픽 수신, 자원 격리를 결정한다.
Probe는 컨테이너 상태를 판단하는 질문이다.
Resource request와 limit은 scheduler와 runtime이 CPU와 memory를 다루는 기준이다.
이 둘을 잘못 설정하면 애플리케이션 코드가 정상이어도 재시작 반복, 트래픽 제외, OOMKilled, CPU throttling이 발생한다.
Spring 백엔드는 JVM 기동 시간, warm-up, DB 연결, thread pool, heap 사용량을 고려해 값을 정해야 한다.
Probe 구분
Kubernetes에는 주로 세 가지 probe가 있다.
- startupProbe: 애플리케이션이 처음 뜨는 동안 충분히 기다린다.
- readinessProbe: 지금 요청을 받아도 되는지 판단한다.
- livenessProbe: 컨테이너를 재시작해야 할 만큼 회복 불가능한지 판단한다.
readiness 실패는 Pod를 Service endpoint에서 제외한다.
liveness 실패는 컨테이너 재시작으로 이어진다.
따라서 DB가 잠시 느린 상태를 liveness 실패로 만들면 재시작 폭주가 발생할 수 있다.
Probe 예시
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 3
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
periodSeconds: 5
failureThreshold: 30startupProbe가 있으면 기동이 느린 Spring 애플리케이션을 liveness가 너무 빨리 죽이는 문제를 줄일 수 있다.
readiness는 필수 의존성이 준비되지 않았을 때 트래픽을 늦추는 데 사용한다.
Resource request와 limit
request는 Pod를 배치할 때 필요한 최소 자원 선언이다.
limit은 컨테이너가 사용할 수 있는 최대 자원 경계다.
resources:
requests:
cpu: "500m"
memory: "768Mi"
limits:
cpu: "1"
memory: "1024Mi"CPU limit에 자주 닿으면 throttling으로 응답 시간이 길어질 수 있다.
Memory limit을 넘으면 컨테이너가 OOMKilled 될 수 있다.
JVM은 container memory를 인식하지만 heap, metaspace, direct memory, thread stack, native memory를 모두 고려해야 한다.
Spring JVM 설정
Kubernetes memory limit과 JVM heap 설정은 함께 봐야 한다.
env:
- name: JAVA_TOOL_OPTIONS
value: "-XX:MaxRAMPercentage=70 -XX:InitialRAMPercentage=50"memory limit이 1024Mi인데 heap을 900Mi로 잡으면 native memory와 thread stack 때문에 OOMKilled가 날 수 있다.
thread pool과 connection pool도 memory와 CPU 사용량에 영향을 준다.
부하 테스트 없이 request/limit을 너무 낮게 잡으면 평소에는 괜찮다가 peak traffic에서 장애가 난다.
장애 신호
- Pod가 CrashLoopBackOff와 OOMKilled를 반복한다.
- readiness 실패로 Service endpoint가 줄어든다.
- liveness 실패 직후 재시작이 늘고 오류율이 더 커진다.
- CPU throttling 증가와 응답 시간 상승이 같이 나타난다.
- 배포 직후 startup 시간이 probe 제한보다 길어 새 Pod가 준비되지 못한다.
- memory 사용량은 limit 근처인데 heap dump나 GC 로그가 없다.
- HPA가 scale-out해도 각 Pod의 startup이 느려 복구가 늦다.
이 신호는 probe와 resource가 애플리케이션 특성을 반영하지 못한다는 뜻이다.
관찰 명령
kubectl describe pod order-api-xxxxx
kubectl top pod
kubectl get events --sort-by=.lastTimestamp
kubectl get endpoints order-apidescribe pod에서는 probe 실패, OOMKilled, image pull, scheduling 실패 같은 event를 본다.
kubectl top은 순간값이므로 장기 추이는 metric 시스템에서 함께 확인해야 한다.
Spring 로그에서는 startup time, GC pause, DB connection timeout, thread pool saturation을 같이 본다.
안전한 완화 조치
- startup이 느리면 startupProbe 또는 initialDelay를 조정한다.
- 일시적 의존성 지연은 liveness가 아니라 readiness로 표현한다.
- OOMKilled가 반복되면 memory limit, JVM heap, thread 수를 함께 조정한다.
- CPU throttling이 심하면 CPU limit 완화 또는 request 조정을 검토한다.
- readiness 실패 Pod가 많으면 배포 속도를 늦추고 maxUnavailable을 줄인다.
- probe endpoint 자체가 무거우면 더 가벼운 상태 확인으로 나눈다.
완화는 단순히 threshold를 크게 키우는 것이 아니라 어떤 상태를 어떤 probe가 표현해야 하는지부터 맞춰야 한다.
하지 말아야 할 대응
- 모든 의존성을 liveness에 넣지 않는다.
- OOMKilled 원인 확인 없이 replica 수만 늘리지 않는다.
- CPU throttling을 무시하고 timeout만 늘리지 않는다.
- readiness를 제거해 배포 직후 트래픽을 바로 받게 하지 않는다.
- resource limit을 없애 모든 Pod가 node 자원을 경쟁하게 두지 않는다.
인프라 담당자와 공유할 자료
- namespace, Deployment, Pod 이름
- probe path, timeout, period, threshold
- request/limit 값과 JVM option
- OOMKilled, throttling, readiness 실패 시각
- Pod별 CPU/memory 추이
- 배포 시각과 rollout strategy
- Spring startup time, GC, thread, DB connection 로그
공유 자료는 Kubernetes event와 JVM 신호를 같은 시간축으로 맞춰야 한다.
운영 체크리스트
- startup, readiness, liveness의 목적이 분리되어 있는가?
- readiness endpoint가 요청 처리 가능성을 반영하는가?
- liveness가 일시적 의존성 장애로 재시작 폭주를 만들지 않는가?
- JVM heap과 memory limit이 함께 계산되어 있는가?
- CPU throttling과 응답 시간 관계를 볼 수 있는가?
- 배포 전략이 readiness 실패를 감안하는가?
확인 질문
확인 질문
- readiness 실패와 liveness 실패의 결과는 어떻게 다른가?
- readiness 실패는 트래픽 제외이고, liveness 실패는 컨테이너 재시작이다.
- Spring JVM에서 memory limit만 보고 안전하다고 할 수 없는 이유는 무엇인가?
- heap 외에도 metaspace, direct memory, thread stack, native memory가 필요하기 때문이다.
- probe와 resource limit이 잘못되면 어떤 장애가 생기는가?
- 재시작 반복, endpoint 제외, OOMKilled, CPU throttling, 배포 지연이 발생할 수 있다.
리뷰 체크포인트
- probe별 목적과 실패 결과가 구분되어 있는가?
- resource request와 limit이 부하와 JVM 설정을 반영하는가?
- OOMKilled와 CPU throttling 관찰 방법이 있는가?
- startup이 느린 애플리케이션을 고려했는가?
- probe endpoint가 너무 무겁지 않은가?