컨테이너를 동적으로 생성하거나 현황을 조회하는 CTF 문제 관리 기능은 Hack Playground 서비스의 핵심 비즈니스 중 하나다.
이 기능은 Kubernetes API와 빈번하게 통신하며, 성격상 IO bound 작업에 가까워서 자연스럽게 Java 가상 쓰레드 도입을 검토했다.
가상 쓰레드의 개념부터 소개해야 하나 고민했지만 다행히 예전에 공부한 내용이 있다.
Java도 한다 경량 쓰레드 (Virtual Thread)
봄(Spring)은 왔는가?Java의 위대한 산물인 가상 쓰레드는 분명 JVM 생테계에 엄청난 열풍을 일으켰음에 의심할 여지가 없다.많은 개발자들이 그 패러다임에 발맞춰서 프레임워크를 개선하고 있듯
downfa11.tistory.com
IO 대기 비용을 줄일 수 있는지 데이터로 확인하고 도입의 근거로 뒷받침하고자 실험을 준비했다. 실험 과정에서 K8s 통신과 별개로, DB 쪽 로직도 함께 테스트하며 다양한 성능 데이터를 쌓는 목적을 두었다.
그 결과, 의도하지 않았던 흥미로운 현상을 발견할 수 있었다.
운영 중인 서비스에서 performance_schema를 기준으로 가장 요청 빈도가 높은 쿼리를 대상으로 가상 쓰레드 도입 전·후 성능 테스트를 진행했다.
실험 과정에서 Grafana 대시보드를 항상 켜둘 수 없고, 매번 초기화할 때마다 소스를 등록하고 ID로 대시보드를 가져오는 번거로움이 있었다.
이를 줄이고, 향후 여러 실험에서도 동일한 환경을 재사용할 수 있도록 선언적 관리 방식을 적용했다.
그 과정에서 모든 Grafana 대시보드를 직접 구축했으며, 파일 구조는 아래와 같다.
Folder PATH listing
Volume serial number is 707A-1D92
C:.
│ docker-compose.yml
│ prometheus.yml
│ README.md
└───grafana
├───dashboards
│ grafana-2.json
│ grafana.json
│
└───provisioning
├───dashboards
│ dashboard.yml
│
└───datasources
datasource.yml
이 구조 덕분에 모든 대시보드를 선언적으로 관리할 수 있었고, 매번 Grafana를 초기화해도 환경 재사용과 테스트 일관성을 확보할 수 있었다.
테스트 환경은 서로 영향을 주지 않도록 독립된 클라우드 환경에서 격리했으며, 실험 시 차이는 가상 쓰레드 여부의 환경변수만 적용했다.
모든 실험은 동일 환경에서 2~3회 정도의 warm-up 후 진행하여 안정적인 측정을 확보했다.
관측된 사실부터 정리하면 다음과 같다.
별 생각없이 k8s api 로직만 보고 '흠 나아졌군' 넘어갈 뻔했지만 환경 구축해둔게 아까워서 여러 데이터를 쌓으려다 얻어걸렸다.
특히 눈에 띈 지표는 다음과 같다.

처리량 자체는 큰 차이가 없었다. 하지만 DB 커넥션을 기다리는 pending 쓰레드 수에서 압도적인 차이가 발생했다.

여기서 분석 결과가 드러난다.
병목 지점이 애플리케이션 쓰레드에서 DB Connection Pool로 이동했다.
가상 쓰레드의 생성 비용이 저렴하다 보니, 제한된 DB 커넥션을 차지하기 위한 경쟁이 더욱 치열해졌다.
결과적으로 커넥션 고갈이 빠르게 발생하고, 대기 큐 지연이 길어지는 현상이 나타난 것이다.
가상 쓰레드 환경에서 중요한 건 동시 요청을 최대한 처리하는 것이 아니라, DB에 부담을 주지 않으면서 핵심 요청만 빠르게 처리하는 것이라 생각했다.
튜닝의 핵심은 하나다.
더 느려지기 전에 얼른 멈춰야한다. 즉, 커넥션을 오래 기다리게 하지 않는다.
이를 위해 HikariCP 설정을 다음과 같이 조정했다.
가상 쓰레드쪽은 일정 시간 지나도록 응답이 오지 않으면 timeout 처리한 결과:


솔직히 별 고민 없이 도입할 정도로 막연하게 자바 진영의 최종병기쯤으로 여겨왔다.
막상 실험 결과가 기존 상식과 큰 차이를 보이니 당황했고, 그만큼 새롭게 느껴서 블로그에 남겼다.
결국 성능 개선의 핵심은 가상 쓰레드 자체가 아니라, HikariCP Timeout을 통한 DB 부하 제어였다.
HikariCP Connection Acquire Time(p95): 30.1 → 1.77 (sec)
DB 앞에서 무제한 대기열이 형성되던 상황이 timeout 기반의 빠른 실패 전략으로 완화되면서, DB 부하는 줄고 핵심 비즈니스 요청의 응답성은 오히려 개선됐다.
이번 실험에서 얻은 결론은 단순하다.
가상 쓰레드 환경에서는 얼마나 작업을 붙들고 있을 것인가?에 더욱 신경 써야한다는 점을 새로 배웠다.
출처 및 인용.
지구용사 선가드
| ArgoWorkflows: 대용량 워크플로우 아카이브 조회시 Out of sort memory 해결 (0) | 2026.01.12 |
|---|---|
| Cursus: BloomFilter를 이용한 컨슈머 벤치마크의 정확성 검사 확장 (0) | 2026.01.03 |
| Cursus: Tabellarius CDC(Change Data Capture) 설계 (0) | 2025.12.30 |
| 오픈소스 입문자를 위한 Kubernetes 지역화: 누락된 문서 탐지 스크립트 구현 (1) | 2025.12.22 |
| [논문 직역] In Search of an Understandable Consensus Algorithm (0) | 2025.12.07 |