콘텐츠로 이동

스레드 풀 & 커넥션 풀 튜닝 — 부하테스트 병목 해결

부하테스트에서 VU를 올릴수록 응답 시간이 갑자기 치솟는다면 풀(Pool) 고갈이 원인인 경우가 많습니다.

스레드와 DB 커넥션을 요청마다 새로 생성하면:

스레드 생성 비용: ~1ms
DB 커넥션 생성: ~5~50ms (TCP 핸드셰이크 + 인증)
초당 1,000 요청이면:
→ 커넥션 생성에만 초당 5~50초 소비 → 불가능

풀은 미리 만들어 둔 자원을 재사용하여 이 비용을 제거합니다.

application.yml
server:
tomcat:
threads:
max: 200 # 최대 스레드 수 (기본값: 200)
min-spare: 20 # 대기 스레드 최솟값
accept-count: 100 # 대기 큐 크기 (스레드 소진 시 대기)
connection-timeout: 5000 # 5초

적정 스레드 수 계산:

스레드 수 = 목표 TPS × 평균 응답시간(초)
예시: 목표 500 TPS, 평균 응답 200ms
→ 500 × 0.2 = 100 스레드
여유분 20% 추가 → 120 스레드

Node.js (단일 스레드 + Worker Threads)

섹션 제목: “Node.js (단일 스레드 + Worker Threads)”

Node.js는 이벤트 루프 기반이라 스레드 풀 개념이 다릅니다.

const { Worker, isMainThread, workerData } = require('worker_threads');
// CPU 집중 작업만 Worker로 오프로드
if (isMainThread) {
// libuv 스레드 풀 크기 설정 (파일 I/O, crypto 등)
process.env.UV_THREADPOOL_SIZE = 16; // 기본값: 4
function runHeavyTask(data) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, { workerData: data });
worker.on('message', resolve);
worker.on('error', reject);
});
}
}
application.yml
spring:
datasource:
hikari:
maximum-pool-size: 20 # 최대 커넥션 수
minimum-idle: 5 # 최소 유휴 커넥션
connection-timeout: 3000 # 커넥션 획득 대기 최대 3초
idle-timeout: 600000 # 유휴 커넥션 10분 후 반납
max-lifetime: 1800000 # 커넥션 최대 수명 30분
validation-timeout: 1000 # 커넥션 유효성 검사 1초

HikariCP 적정 풀 크기 공식 (PostgreSQL 권장):

풀 크기 = (CPU 코어 수 × 2) + 유효 스핀들 수
예시: 8코어, SSD 환경
→ (8 × 2) + 1 = 17 → 20개로 반올림
※ 이 공식은 놀랍도록 작은 값을 제시합니다.
DB 서버 관점에서 커넥션이 많을수록 경합이 증가합니다.
from sqlalchemy import create_engine
engine = create_engine(
"postgresql://user:pass@host/db",
pool_size=10, # 기본 풀 크기
max_overflow=20, # pool_size 초과 시 추가 생성 (임시)
pool_timeout=3, # 커넥션 대기 최대 3초
pool_recycle=1800, # 30분마다 커넥션 갱신 (방화벽 끊김 방지)
pool_pre_ping=True, # 사용 전 커넥션 유효성 확인
)
const Redis = require('ioredis');
const redis = new Redis({
host: 'redis-host',
port: 6379,
maxRetriesPerRequest: 3,
// 커넥션 풀 설정
lazyConnect: true,
enableOfflineQueue: false, // 연결 끊기면 즉시 실패 (큐 쌓임 방지)
});
// 클러스터 환경
const cluster = new Redis.Cluster(['redis-node:6379'], {
scaleReads: 'slave', // 읽기는 슬레이브로 분산
maxRedirections: 3,
});
커넥션 풀 고갈 증상:
- 에러: "Connection pool timeout" / "HikariPool-1 - Connection is not available"
- 응답 시간: 요청이 들어올수록 3초, 5초, 30초로 증가
- APM: DB Span 앞에 긴 대기 시간(Connection wait)
# Prometheus 스크레이프 대상 추가
# Spring Boot Actuator + Micrometer 연동 시 자동 노출
# 활성 커넥션 수
hikaricp_connections_active{pool="HikariPool-1"}
# 대기 중인 요청 수 (이 값이 올라가면 위험)
hikaricp_connections_pending{pool="HikariPool-1"}
# 커넥션 획득 평균 대기 시간 (ms)
hikaricp_connections_acquire_seconds_sum / hikaricp_connections_acquire_seconds_count * 1000
visitor count

이 가이드를 내 서비스에 직접 적용해 보세요.

TestForge 무료 스캔 시작 →