HPA behavior의 stabilizationWindowSeconds, 이거 하나 바꿨더니 야간 알람이 사라졌다

오늘 알게 된 건 아니고, 얼마 전부터 팀 내부에서 오토스케일링 튜닝하다가 정리한 팁이다. 근데 이거 모르는 분들이 의외로 꽤 있어서 짧게 남긴다.
HPA behavior 필드는 v2에서 나온 뒤로 GA 된 지가 좀 됐는데, 아직도 기본값 그대로 쓰는 팀이 많더라. 그 중에서도 stabilizationWindowSeconds가 특히 문제다.
뭐가 문제였냐면
트래픽이 규칙적으로 확 튀었다가 3-4분 안에 원상복구되는 서비스가 하나 있다. 이벤트 배너 서비스인데, CPU가 순간 60%까지 튀고 30초쯤 지나면 20% 아래로 떨어진다.
HPA 기본 설정으로 놔뒀더니 이런 흐름이 반복됐다:
- 트래픽 스파이크 → 5개 → 12개로 스케일 업
- 30초 뒤 트래픽 원상복구
- 5분 뒤 (기본 downscale stabilization window) 스케일 다운 시작
- 다시 스파이크 → 스케일 업
문제는 스케일 업이 즉시(0초 stabilization) 반응하는데, 사실 이 서비스는 그렇게 빨리 반응 안 해도 됐다. 오히려 30초 정도 지켜보고 지속되는 스파이크에만 반응해도 충분한 워크로드. 근데 매번 오버 프로비저닝되니까 노드도 튀고, Karpenter가 노드 추가하려다가 이미 스파이크가 끝나서 다시 소거하고, 새벽에 이 짓을 반복하고 있었다.
그냥 이렇게 하면 된다
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: event-banner
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: event-banner
minReplicas: 3
maxReplicas: 30
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleUp:
stabilizationWindowSeconds: 60 # 기본 0 → 60초로
policies:
- type: Percent
value: 50
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 600 # 기본 300 → 600초로
policies:
- type: Percent
value: 20
periodSeconds: 60
핵심은 두 줄이다.
scaleUp.stabilizationWindowSeconds: 60 — 스파이크가 최소 60초 이상 지속되어야 스케일업. 짧은 스파이크는 무시.
scaleDown.stabilizationWindowSeconds: 600 — 스케일 다운은 더 보수적으로. 트래픽 잦아든 것 같아도 10분은 지켜보고 내리자.
왜 이렇게 잡나
HPA 컨트롤러는 매 15초마다 desired replicas를 계산한다. stabilizationWindowSeconds는 최근 그 시간 창 안의 desired 값 중 스케일 방향에 맞는 극값을 골라서 실제 replicas로 반영한다.
- 스케일 업 방향에서 window가 60초면 → 최근 60초 desired 중 최솟값을 채택. 즉 스파이크 몇 초 있었다고 바로 안 늘림.
- 스케일 다운 방향에서 window가 600초면 → 최근 10분 desired 중 최댓값을 채택. 즉 순간 낮아졌다고 바로 안 줄임.
이게 flap 방지의 핵심이다. policies의 Percent, Pods, periodSeconds는 실제로 얼마나 빨리 늘리고 줄일지를 정하는 거고, stabilizationWindow는 "정말 늘리거나 줄여도 되나?"의 판단 지연을 넣는 거라 다른 축이다. 헷갈리는 분들 많다.
실제 결과
바꾸고 하루 만에 야간 오토스케일 알람이 확 줄었다. Karpenter 노드 launch/terminate 이벤트도 24시간 기준 40건대에서 8-10건대로. 팀에서 다들 좋아함.
솔직히 기본값이 별로다. scaleDown.stabilizationWindowSeconds: 300은 대부분의 API 서버에는 너무 짧고, scaleUp: 0은 워크로드에 따라선 너무 공격적이다. 서비스 특성 보고 반드시 튜닝하자.
참고
혹시 다른 튜닝 감각 쓰시는 분 있으면 어떻게 잡는지 궁금하다.