TL;DR — submit 모듈 WebFlux→MVC 전환 효과를 부하테스트로 검증하던 중, 정작 sign-in이 동시 500에서 p50 25,242ms로 붕괴하는 걸 발견했다. 원인은 노드 자원 부족이 아니라(80코어 중 1%만 사용) auth/course 파드가
limits.cpu=2·replicas=1에 고정된 것. 수직(코어↑) + 수평(KEDA) + 이중화 + HikariCP 커넥션 예산 + N+1 잔여 제거로 sign-in 25s→0.16s, 성적조회 15.7s→2.2s. 단, KEDA의 CPUUtilization이 limits가 아닌requests기준이라 조기 스케일되던 함정을AverageValue로 정정했다.
전환 대상이던 submit 경로는 목표대로 대폭 개선됐다(제출 p95 2,320→271ms, SLA(300ms) 위반 77%→4.5%). 그런데 submit이 빨라지자 가려져 있던 sign-in 병목이 드러났다.
| 라벨 | 부하 | p50 | p95 |
|---|---|---|---|
| POST sign-in (auth) | 동시 500 | 25,242ms | 44,166ms |
| 성적 조회 (course) | 동시 50 | 15,729ms | 18,602ms |
| gateway 라우팅 | 동시 500 | 정상(<150ms) | 정상 |
전체 응답시간(p95 41초)은 사실상 sign-in 하나가 끌어올린 값이었다. 모듈별로 나눠 보니 course 성적 조회도 단 50명에서 붕괴했고, gateway는 멀쩡했다.
kubectl top/describe node, HPA 상태BCryptPasswordEncoder.matches() = CPU 바운드(호출당 ~80ms). auth-server는 replicas=1, limits.cpu=2. 500 로그인이 2코어에 몰리면 처리 상한 ~25/s를 초과 → Tomcat 스레드풀 큐잉 → 25초.replicas=1 · 2코어라 동반 기아.max_connections=151 (HikariCP 풀 × replica 합산 한계).1) 스레드풀 증설이 아니라 CPU 추가
bcrypt는 CPU 바운드라 Tomcat max-threads를 늘려도 총 처리량은 불변(오히려 컨텍스트 스위칭으로 꼬리지연 악화). 코어를 늘리는 것만이 답.
2) 수직 + 수평 + 이중화 (노드 70% = 56코어 예산 내)
| 모듈 | 변경 |
|---|---|
| auth-server | KEDA min2/max4 + limits 2→4코어 |
| course-server | KEDA min2/max3 + limits 2→4코어 |
| gateway-server | replicas 2 정적 이중화 + resources 경계 신규 |
| submit-server | KEDA min 1→2 |