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 세션은 이렇게 연결됨
- 사용자가 웹에서 버튼 클릭 (HTTP 요청)
- Spring → Controller → Service
- 커넥션 풀에서 DB 커넥션 하나 빌림 → DB 세션 연결됨
- 쿼리 실행 후 커넥션 close() → 세션은 커넥션 풀로 반환됨 (죽지 않음)
📌 사용자 요청이 끝났다고 해서 DB 세션이 바로 죽지 않음
Java 커넥션 풀(Hikari 등)은 DB 세션을 계속 유지하다가 다음 요청에 재사용함
✅ 비유로 이해해보기
요소 비유
클라이언트 요청 | 전화 걸기 (끊기면 끝) |
DB 커넥션 풀 | 전화를 걸기 위해 대기 중인 콜센터 상담원 |
DB 세션 | 상담원이 지금 누군가와 통화 중인지 아닌지 상태 |
커넥션 반환 | 통화 종료 후 상담원이 다시 대기열로 돌아가는 것 |
✅ 정리
"HTTP 요청은 끝나는데, 서버와 DB는 연결 유지하는 거야?"
✅ 네! 웹 요청은 stateless지만, DB 커넥션은 커넥션 풀에서 살아 있고, 세션도 Oracle에서 유지됩니다.
"DB와 서버 사이에도 세션 관리하는 거야?"
✅ 맞습니다. Oracle은 커넥션마다 고유한 세션을 갖고, v$session에 기록되고,
JDBC 커넥션이 닫힐 때 그 세션도 함께 종료되거나 풀로 반환됩니다.
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 메모리 확인 |
'🛢️ Database' 카테고리의 다른 글
📘 읽기전용 DB분산구조는 왜필요한가(Read Replication) – Primary / Replica 구조 | 읽기 부하 분산 | 실시간 복제 이슈 (0) | 2025.04.07 |
---|---|
🔐 트랜잭션 격리 수준과 세션 관계 – 성능과 일관성의 줄다리기 | READ COMMITTED, SERIALIZABLE | 트랜잭션과 세션/커넥션의 생명 주기 관계 (0) | 2025.04.06 |
🩺 오라클 기준 DB 세션 모니터링 방법( v$session, v$process, v$sql ) | 세션정보 확인 추적 -> 문제세션 찾는 방법 -> 자동 모니터링 알람 설정 (0) | 2025.04.06 |
🔧 커넥션 풀 튜닝 전략 – 성능 병목을 잡는 핵심 포인트 (0) | 2025.04.06 |
데이터베이스_index (0) | 2025.04.06 |
댓글