본문 바로가기
🛢️ Database

[DB] HikariCP 커넥션 풀 왜쓰는거야? | 작동 흐름 | 커넥션 풀 없는 구조 vs 있는 구조 비교 | 세션모니터링

by 죄니안죄니 2025. 4. 6.

1. HikariCP 커넥션 풀의 작동 흐름

📦 1. 애플리케이션이 시작되면 설정한 커넥션 수만큼 DB연결을 해 놓음(Pool)

  • Spring Boot가 실행되면서 HikariDataSource가 초기화 (설정에 따라 미리 최소 커넥션 수만큼 Oracle DB에 연결. 예: minimumIdle = 5이면, 최소 5개의 커넥션을 풀에 만들어둠)

👤 2. 사용자가 어플리케이션에서 DB접속을 요구하는 요청을 보내는 경우 풀에서 커넥션 하나 빌림(getConnection())

  • 사용자 A가 로그인 버튼 클릭 → 컨트롤러 호출
  • 서비스 계층에서 DB 접근 필요
  • 👉 풀에서 커넥션 하나 빌림 (getConnection())

🔁 3. 서비스 로직의 쿼리 실행 (ps.executeQuery())

  • 빌린 커넥션으로 쿼리 실행: SELECT, INSERT, UPDATE 등
  • 이때 Oracle DB에 하나의 세션이 바인딩되어 작업 수행

🧹 4. 커넥션 반납 (close(), java try-with-resources문법)

  • Java에서 conn.close() 호출
  • 진짜로 연결 끊는 게 아니라, 풀로 반환
  • 다음 요청이 오면 재사용됨 (속도 빠름!)

🔄 1~4 반복

  • 사용자 B가 요청 → 또 커넥션 하나 빌림 → 반납
  • 최대 동시에 처리할 수 있는 수는 maximumPoolSize에 따라 제한됨

✅ 그림으로 이해하기

[Spring Boot 시작] ─────> [Hikari 풀 생성: 10개 커넥션 DB 연결 유지]

사용자 A 요청 ──> 커넥션 하나 빌림 ──> DB 작업 ──> 반납
사용자 B 요청 ──> 또 하나 빌림 ──> DB 작업 ──> 반납
...
최대 10개까지 동시에 가능 → 초과 시 대기 or 에러

✅ 이 구조의 핵심 장점

장점 설명

연결 속도 빠름 매번 연결/종료 안 해도 됨
세션 재사용 DB 부하 줄고 응답 빨라짐
풀 크기 조절 가능 최대 동시 접속 제어 가능
트랜잭션 안정성↑ 한 요청 안에서 동일 커넥션 유지 가능

💡 실무 팁

  • try-with-resources로 커넥션 반납 보장할 것!
try (Connection conn = dataSource.getConnection()) {
    // 쿼리 실행
} // 여기서 자동 반납
  • 커넥션을 반납 안 하면 풀 고갈돼서 ConnectionTimeoutException 터집니다.

🔥 결론

✔️ 애플리케이션 시작 시 커넥션 풀 구성되고,

✔️ 사용자 요청마다 풀에서 커넥션 하나 빌려서 쓰고, 끝나면 다시 반납하는 구조입니다!


2. 커넥션 풀 없는 구조 vs 커넥션 풀 있는 구조 비교

🧪 실험 시나리오

  • Java 애플리케이션에서 Oracle DB에 단순 SELECT 요청을 1000번 반복
  • 하나는 직접 커넥션 연결/종료 (풀 없음)
  • 하나는 HikariCP로 커넥션 풀 사용
  • 수행 시간 + Oracle 세션 수 + 시스템 자원 사용 비교

⚙️ 코드 예시

🔴 커넥션 풀 없을 때 (매번 연결) DriverManager.getConnection(...)

for (int i = 0; i < 1000; i++) {
    try (Connection conn = DriverManager.getConnection(url, user, pass);
         PreparedStatement ps = conn.prepareStatement("SELECT 1 FROM dual");
         ResultSet rs = ps.executeQuery()) {
        rs.next();
    }
}
  • 직접 DB 접속. 매 접속**( 1000번) 새로 연결. 즉** Oracle은 매번 새로운 세션 생성/종료
  • 작업 끝나고 close() 하면 진짜로 연결 끊김
  • CPU + 네트워크 부하 + 인증 비용 ↑
  • ✅테스트용이나 일회성 쿼리. ❌ 실무 서비스에서는 거의 안 씀

🟢 커넥션 풀 있을 때 (재사용) HikariDataSource 이용

DataSource ds = new HikariDataSource(config);

for (int i = 0; i < 1000; i++) {
    try (Connection conn = ds.getConnection();
         PreparedStatement ps = conn.prepareStatement("SELECT 1 FROM dual");
         ResultSet rs = ps.executeQuery()) {
        rs.next();
    }
}
  • 애플리케이션 시작 시 내부적으로 DB 커넥션 풀을 먼저 만들어 둠 (10~20개의 커넥션) 그리고 계속 재사용
  • getConnection()을 하면 풀 안에서 하나 꺼내줌 (필요하면 새로 만들기도 하고, idle 커넥션 재사용도 함)
  • conn.close()를 해도 실제로 끊지 않고 풀에 반납만 함
  • 응답 시간 획기적으로 줄어듦. 성능도 빠르고, DB 세션도 안정적으로 관리 가능 ✅

📊 결과 비교 (실제 측정 예시)

항목 커넥션 풀 없음 커넥션 풀 사용

평균 응답 시간 (1000회) 약 5~8초 이상 약 0.3~0.5초
Oracle 세션 생성 수 1000개 (단기 폭증) 10~20개 (지속 유지)
CPU 사용률 급등 안정적
네트워크 비용 높음 낮음
세션 재사용 ❌ 매번 새로 생성 ✅ 계속 재사용

🔥 결론

💣 커넥션 풀이 없으면 DB는 매번 세션/쓰레드/메모리를 새로 쓰고,

💡 커넥션 풀을 쓰면 재사용 덕분에 성능도 빠르고 자원도 아낍니다.


3. 웹세션(HTTP세션)과 DB세션 비교 ㅡ 웹 HTTP통신은 stateless인데 (웹서버에 컨넥션이 유지되지 않음), DB서버의 경우 커넥션이 지속적으로 유지되고 있다. 별개의 개념

✅ 핵심 개념 먼저 요약

🔸 클라이언트 ↔ 웹 서버:

요청할 때마다 통신(HTTP) 열고, 응답 끝나면 연결 종료 (stateless)

🔸 웹 서버 ↔ DB 서버:

DB 커넥션은 계속 유지되거나 풀에서 재사용

(즉, 세션이 "살아 있음")

🔸 둘은 완전히 별개이며,

DB 세션은 HTTP 요청이 끝나도 바로 사라지지 않음!


✅ 그림으로 표현하면

[사용자]──HTTP 요청────▶ [웹 서버] ──JDBC 커넥션 유지──▶ [Oracle DB]

            ▲ 요청 끝나면 연결 끊김 (stateless)
                                        ▲ 커넥션 풀에서 유지됨 (session 살아 있음)

✅ 세션 개념 비교

구분 클라이언트 ↔ 웹 서버 (HTTP 세션) 웹 서버 ↔ DB (DB 세션)

프로토콜 HTTP (stateless) JDBC / TCP (stateful)
기본 연결 요청마다 새로 연결 커넥션 풀로 유지 또는 재사용
세션 유지 웹서버가 JSESSIONID로 관리 (쿠키) Oracle이 세션 객체로 관리 (v$session)
세션 종료 브라우저 닫거나 타임아웃 커넥션 close(), 타임아웃 등
대표 예시 로그인 세션 ALTER SESSION 설정 유지

✅ 클라이언트 요청과 DB 세션은 이렇게 연결됨

  1. 사용자가 웹에서 버튼 클릭 (HTTP 요청)
  2. Spring → Controller → Service
  3. 커넥션 풀에서 DB 커넥션 하나 빌림 → DB 세션 연결됨
  4. 쿼리 실행 후 커넥션 close() → 세션은 커넥션 풀로 반환됨 (죽지 않음)

📌 사용자 요청이 끝났다고 해서 DB 세션이 바로 죽지 않음

Java 커넥션 풀(Hikari 등)은 DB 세션을 계속 유지하다가 다음 요청에 재사용


✅ 비유로 이해해보기

요소 비유

클라이언트 요청 전화 걸기 (끊기면 끝)
DB 커넥션 풀 전화를 걸기 위해 대기 중인 콜센터 상담원
DB 세션 상담원이 지금 누군가와 통화 중인지 아닌지 상태
커넥션 반환 통화 종료 후 상담원이 다시 대기열로 돌아가는 것

✅ 정리

"HTTP 요청은 끝나는데, 서버와 DB는 연결 유지하는 거야?"

✅ 네! 웹 요청은 stateless지만, DB 커넥션은 커넥션 풀에서 살아 있고, 세션도 Oracle에서 유지됩니다.

"DB와 서버 사이에도 세션 관리하는 거야?"

✅ 맞습니다. Oracle은 커넥션마다 고유한 세션을 갖고, v$session에 기록되고,

JDBC 커넥션이 닫힐 때 그 세션도 함께 종료되거나 풀로 반환됩니다.

웹세션과 DB세션 차이


4. DB 커넥션을 계속 유지하고 있으면 서버에 부담은 없을까? 커넥션 풀로 잘 관리하면 충분히 감당 가능하다

📌 먼저 짚고 갈 개념

용어 설명

DB 연결(Connection) 애플리케이션 ↔ DB 사이의 통신 연결
세션(Session) DB에서 연결된 사용자 단위로 관리되는 정보 (트랜잭션 상태, 설정 등)
커넥션 풀(Connection Pool) DB 연결을 재사용하기 위해 미리 만들어 놓고 관리하는 풀

✅ 왜 "유지한다고 부담이 되는가"?

Oracle이든 PostgreSQL이든, DB 세션 하나당 다음 리소스를 차지합니다:

자원 설명

메모리 Oracle은 세션마다 PGA(Process Global Area) 사용
프로세스 / 쓰레드 DB마다 모델 다르지만 커넥션 하나당 최소 쓰레드 하나 사용
세션 오브젝트 v$session에 세션 상태, 트랜잭션, NLS 설정 등 저장

📌 1000개 세션이 떠 있다?

그만큼의 메모리 + 쓰레드 리소스를 소모 중!


✅ 그런데도 실무에서 왜 계속 유지하냐?

매번 연결/끊기를 하면 더 많은 비용이 발생하기 때문입니다.

매번 연결/끊기 방식의 문제

  • DB 접속 시: 네트워크 핸드셰이크, 인증 처리, 세션 생성
  • 끊을 때: 세션 제거, 자원 해제
  • → 초당 수십~수백 요청이 오면? 성능 심각하게 저하

✅ 그래서 등장한 구조 = 커넥션 풀

장점 설명

✅ 연결 재사용 끊지 않고 재사용 → 성능 매우 좋음
✅ 세션 수 제한 동시에 유지할 DB 연결 수를 제한 가능
✅ 불필요한 커넥션 제거 유휴시간 초과 시 자동 정리 (idleTimeout)
✅ 설정 자동화 연결 시 자동 ALTER SESSION 등 설정 가능

🔧 실무에서는 어떻게 관리하나?

대표 커넥션 풀 설정 예 (HikariCP 기준):

spring:
  datasource:
    hikari:
      maximum-pool-size: 20         # 동시에 최대 20개만 연결
      minimum-idle: 5               # 최소 유지 수
      idle-timeout: 600000          # 10분 이상 유휴 시 정리
      connection-timeout: 30000     # 커넥션 획득 대기 시간

DB 커넥션 풀(max pool size = 20)은 동시 요청 수 제한이지 동시 사용자 수의 제한을 뜻하진 않습니다. 웹 애플리케이션 사용자 = 10,000명 → 하지만 동시에 DB 작업하는 사용자는 20~50명 정도이고, pool 사이즈 넘는 요청은 순서대로 대기하고(성능 저하, 일부 요청 실패 가능, 타임아웃), 나머지는 DB를 사용하지 않는 화면(정적 페이지, 캐시된 데이터)을 보는 중일 수 있어요.


✅ "그럼 몇 개까지 유지해도 돼요?"

👉 이건 시스템 성능과 DB 서버의 리소스에 따라 다르지만…

  • 일반 웹 서비스: 20~100개 사이
  • 트래픽 많은 서비스: 200~500개
  • 실시간 대용량 처리: 전용 DB 서버, 튜닝 필요

→ Oracle 기준 v$parameter에서 sessions, processes 확인 가능

SHOW PARAMETER sessions;
SHOW PARAMETER processes;

✅ 부가 팁: 연결 못 받는 상황에서 발생하는 대표 에러

상황 에러

커넥션 풀 고갈 ConnectionPoolTimeoutException / HikariPool-1 - Connection is not available
대기 시간 초과 Timeout waiting for connection from pool
DB에서 세션 초과 ORA-00020: maximum number of processes exceeded

✅ 그래서 실무에선?

전략 설명

커넥션 풀 크기 = 예상 동시 요청 수 정도로 설정 일반적으로 20~200 사이 (서비스 성격에 따라 다름)
트랜잭션 시간 최소화 DB 연결을 오래 붙잡고 있으면 풀 고갈됨
캐시, 읽기 전용 DB 분리, 비동기 처리 커넥션 부담 줄이는 핵심 전략
백오프 / 타임아웃 설정 커넥션 못 얻으면 빠르게 실패하거나 큐에 넣기

✅ 요약 정리

항목 설명

DB 연결 유지 → 리소스 사용 O 메모리, 쓰레드, 세션 자원 차지
매번 연결/끊기보다 유지하는 게 낫다 성능 효율 면에서 비교 불가
커넥션 풀을 쓰면 안전하게 유지 가능 개수 제한, 자동 종료, 재사용 가능
실제 부담이 될 수 있다 너무 많은 세션을 열면 DB가 과부하 (모니터링 필요)

5. 실제 DB 세션이 차지하는 리소스를 모니터링하는 SQL

Oracle에서는 v$session, v$process, v$sess_io, v$sesstat 뷰를 통해

현재 세션이 사용하는 CPU, 메모리, IO, 대기 상태 등을 확인할 수 있습니다.


🔍 현재 세션 리스트 + 접속 정보 보기

SELECT s.sid, s.serial#, s.username, s.status,
       p.spid AS os_process_id,
       s.program, s.machine, s.logon_time
FROM v$session s
JOIN v$process p ON s.paddr = p.addr
WHERE s.username IS NOT NULL;

🔍 특정 세션의 리소스 사용량 보기

-- CPU 사용량
SELECT ss.sid, se.value AS cpu_time
FROM v$sesstat se
JOIN v$statname sn ON se.statistic# = sn.statistic#
JOIN v$session ss ON ss.sid = se.sid
WHERE sn.name = 'CPU used by this session'
  AND ss.username IS NOT NULL;

🔍 세션별 I/O 정보

SELECT sid, blocks_read, blocks_written
FROM v$sess_io
WHERE blocks_read > 0 OR blocks_written > 0;

🔍 메모리 사용량 (PGA, UGA)

SELECT s.sid, p.pid,
       p.pga_used_mem, p.pga_alloc_mem,
       p.pga_max_mem
FROM v$session s
JOIN v$process p ON s.paddr = p.addr
WHERE s.username IS NOT NULL;

✅ 정리 요약

목적 뷰 설명

세션 목록 조회 v$session 로그인 사용자, 상태 등
OS 프로세스 확인 v$process DB 세션과 OS 매핑
CPU 사용량 v$sesstat + v$statname 세션 단위 CPU 시간
I/O 상태 v$sess_io 읽기/쓰기 블록 수
메모리 사용 v$process PGA 메모리 확인

댓글