1. 개요

8/13은 배포환경을 대상으로 배달 전 구간을 포함해 13회 실행했다. 초반 런이 계속 병목에 걸렸다. 매칭이 느린 것이 아니라 HikariCP 커넥션 풀이 말라서 요청이 앞단에서 밀렸다. 추적해 보니 CPU를 크게 소모하는 로그인 비밀번호 해싱이 커넥션을 붙잡고 있었고, 유저 세팅 단계에서 고갈된 풀과 스레드가 곧바로 이어지는 부하 단계 지표까지 오염시키고 있었다.

대응으로 로그인 대기열을 도입해 해싱 부하를 격리했고, 최종 런은 통과했다.

이 보고서의 주제는 매칭 알고리즘이 아니라 로그인 단계가 이후 전 구간을 오염시킨 문제다. 매칭 로직 자체의 구조적 문제는 매칭 부하테스트 보고서 (8.12)에 있다.


2. 테스트 조건

항목
규모 드리미 100 · 부르미 100 · 주문 100
주입 속도 초당 20건 (ORDER_RATE=20)
배달 포함 (DELIVERY=1)
실클라이언트 미실행 (WATCH=0)
API https://d3cev4xst074qp.cloudfront.net
DB jdbc:mysql://127.0.0.1:13306/softeer

서버 캐파를 함께 봐야 결과가 읽힌다.

항목 출처
인스턴스 cpus: 1 · mem_limit: 800m docker-compose.yml:26-28
JVM -Xms192m -Xmx192m -Xss512k docker-compose.yml:43-52
톰캣 스레드 server.tomcat.threads.max=100 · accept-count=100 application.properties:77-78
커넥션 풀 maximum-pool-size=10 · minimum-idle=10 · connection-timeout=3000 application.properties:17-22
비밀번호 해싱 PBKDF2WithHmacSHA256 · ITERATIONS = 210_000 PasswordHasher.java:17-20

vCPU가 1개다. 이 값이 이후 모든 분석의 전제가 된다.


3. 초반 런 — 커넥션 풀 고갈

초반 런은 병목이 반복 재현됐고 Hikari 커넥션이 말랐다.

스레드 덤프 (application.properties:71-77)

톰캣 최대 스레드가 기본값(200 이상)이던 시점의 배포 인스턴스에서 스레드가 246개까지 늘었다. 그중 RUNNABLE은 20개, BLOCKED가 187개였다. 스택 1MB 기준으로 246MB가 스레드에만 잡혀 있었다.

스레드가 일하지 않고 막혀 있었다는 뜻이다. 리틀의 법칙으로 필요한 동시성을 계산하면 20 req/s × 2s = 40이므로, 스레드 100이면 4배 여유다. 이후 threads.max=100으로 낮췄다.

Metaspace OOM (docker-compose.yml:36-42)

같은 날 Metaspace 상한 160m가 159MiB에서 차면서 OutOfMemoryError: Metaspace로 JVM이 죽었다. 힙 실사용은 133MiB였다. 이후 MaxMetaspaceSize=256m, -Xss512k로 조정했다.