Computer Science/DB

[DB] DB Connection Pool

깨구르르 2024. 4. 3. 20:11
728x90

1. DB Connection Pool이란?

 

- DB Connection이란?

  • DB를 사용하기 위해 DB와 애플리케이션 간 통신을 할 수 있는 수단
  • DB Connection은 Database Driver와 Database 연결 정보를 담은 URL이 필요함
  • Java의 DB Connection은 JDBC를 주로 이용하는데, URL 타입을 사용함

 


 

- Driver type별로 지정하는 URL 예

Driver URL 설명
oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@ipaddress:1521:ORA7 oracle-DB/thin-Driver
oracle.jdbc.driver.OracleDriver jdbc:oracle:oci7:@ipaddress:1521:ORA7 oracle-DB/OCI-Driver
com.mysql.jdbc.Driver jdbc:mysql://ip_address:3306/database_name mysql
sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbcLdatabase_name jdbc-odbcBridge
com.informix.jdbc.IfxDriver jdbc:informix-sqli://ip:port/dbName:informixserver=sid informix-DB

 


 

- DB Connection 구조

  • 2Tier - 클라이언트로서의 자바프로그램(JSP)이 직접 DB 서버로 접근하여 데이터를 액세스하는 구조
  • 3Tier - 자바 프로그램과 데이터베이스 서버 사이에 미들웨어 계층이 존재하는 구조
    미들웨어 계층은 비즈니스 로직 구현, 트랜잭션 처리, 리소스 관리 등을 담당함

 


 

- JDBC

  • Java DataBase Connectivity
  • 자바 언어로 다양한 종류의 관계형 데이터베이스에 접속하고 SQL문을 수행하여 처리하고자 할 때 사용되는 표준 SQL 인터페이스 API
  • 원래라면 DB마다 연결 방식과 통신 규격이 따로 있기 때문에 프로그램을 DB와 연결한다면, 해당 DB와 관련된 기술적 내용을 배우고 DB가 변경될 시 많은 변경사항이 존재함
  • 하지만 각 DBMS에 맞는 JDBC를 받아주게 되면 쉽게 DBMS를 변경할 수 있게 됨
    👉 DBMS 종류에 상관 없이 하나의 JDBC API를 사용해서 데이터베이스 작업을 처리할 수 있게 됨
  • 자바 애플리케이션에서 데이터베이스에 접근하기 위해서는 JDBC API를 이용해서 데이터베이스에 접근하고, JDBC API는 JDBC 드라이버를 거쳐 데이터베이스와 통신함

JDBC API 사용하는 애플리케이션의 구조

 


 

- JDBC 드라이버

  • 자바 프로그램의 요청을 DBMS가 이해할 수 있는 프로토콜로 변환해주는 클라이언트 사이드 어댑터
  • 각각의 DBMS는 자신에게 알맞은 JDBC 드라이버를 제공하고 있음
더보기

Client-Side Adapter

  • Adapter Pattern 어댑터 패턴으로 개발된 Adapter
  • 어댑터 패턴: 클래스의 인터페이스를 사용자가 기대하는 다른 인터페이스로 변환하는 패턴

👉 JDBC 드라이버는 DB가 달라도 어댑터 패턴으로 개발된 어댑터로 동일한 함수로 동일하게 동작되게 해줌

 


 

- JDBC 실행 과정

  • 첫 번째, DB 벤더에 맞는 드라이버 로드
  • 두 번째, DB 서버의 IP, ID, PW 등을 DriverManager 클래스의 getConnection() 메소드를 사용하여 Connection 객체 생성
  • 세 번째, Connection에서 PreparedStatement 객체를 받음
  • 네 번째, executeQuery를 수행
  • 다섯 번째, ResultSet 객체를 받아 데이터를 처리
  • 마지막, 사용하였던 ResultSet, PreparedStatement, Connection을 close

 

[ 예시 ]

package spms.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import spms.util.DBConnectionPool;
import spms.vo.Member;

/* Dao (Data Access Object)
 * 데이터베이스는 연결하여 데이터를 입출력을 담당하는 클래스
 * 이 클래스로 만들어진 오브젝트를 Dao라고 부른다.
 * */
public class MemberDao {
	
	private String strSelectList = 
			"SELECT mno,mname,email,cre_date FROM members ORDER BY mno ASC";

	DBConnectionPool connPool;
	
	public void setDBConnectionPool(DBConnectionPool connPool) {
		this.connPool = connPool;
	}
	
	/*
	 * Connection 객체 1개로 여러 메서드가 각각의 서블릿에서 호출되면
	 * rollback시 다른 명령에도 영향을 주어서 취소가 되므로
	 * 이제 ConnectionPool을 사용해서 독립적인 명령 처리가 되도록 한다.
	 * 
	Connection connection;
	
	public void setConnection(Connection connection) {
		this.connection = connection;
	}
	*/

	// MemberListServlet에서 필요
	public List<Member> selectList() throws Exception{
		Connection connection = null;	// 추가
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		try {
			// 커넥션풀에서 객체를 빌려옴
			connection = this.connPool.getConnection();	// 추가
			
			stmt = connection.prepareStatement(strSelectList);
			rs = stmt.executeQuery();
			
			List<Member> members = new ArrayList<>();
			
			while(rs.next()) {
				members.add(new Member()
						.setNo(rs.getInt("mno"))
						.setName(rs.getString("mname"))
						.setEmail(rs.getString("email"))
						.setCreatedDate(rs.getDate("cre_date"))
						);
			}
			
			return members;
			
		}catch(Exception e) {
			throw e;
		}finally {
			try {if(rs!=null) rs.close();} catch(Exception e) {}
			try {if(stmt!=null) stmt.close();} catch(Exception e) {}
			
			// 커넥션풀에서 빌려온 Connection 객체를 반납함
			if(connection != null) connPool.returnConnection(connection);
		}
	}
}

 

  • getConnection()
    • DriverManager.getConnection()은 실제 자바 프로그램과 데이터베이스를 네트워크 상에서 연결해주는 메소드
    • 연결에 성공하면 DB와의 연결 상태를 Connection 객체로 표현하여 반환
    • 가장 부하가 많이 걸리는 과정
  • Connection
    • DB 연결 객체
    • 데이터베이스로의 연결 기능을 제공하며, Statement 객체를 생성하는 기능 제공
    • SQL문데이터베이스에 전송하거나, 이러한 SQL문을 커밋하거나 롤백하는 데 사용
    • 보통 Connection 하나 당 트랜잭션 하나를 관리함
      : Mybatis의 SqlSession, Hibernate의 TransactionManager 등의 Close가 이루어지면 Connection을 ConnectionPool에 반납함
  • Statement 또는 PreparedStatement
    : SQL문 실행 객체
  • ResultSet
    : 쿼리문의 결과를 가지는 객체
  • Driver
    : 각 JDBC Driver 벤더에서 구현해야 하는 인터페이스
  • DriverManager
    : 사용될 드라이버를 등록하거나 등록을 해제하는 기능과 DB를 연결하는 기능을 수행함

 


 

- Connection Pool

Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;

try {
	sql = "SELECT * FROM t_board";
    
    // 1. 드라이버 연결 DB 커넥션 객체를 얻음
    conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
    
    // 2. 쿼리 수행을 위한 PreparedStatement 객체 생성
    pstmt = conn.createStatement();
    
    // 3. executeQuery: 쿼리 실행 후
    // ResultSet: DB 레코드 ResultSet에 객체가 담김
    rs = pstmt.executeQuery(sql);
    
} catch (Exception e) {
	e.printStackTrace();

} finally {
	rs.close();
    pstmt.close();
	conn.close();
}

자바에서 DB에 직접 연결해서 처리하는 경우 JDBC Driver를 로드하고 커넥션 객체를 받아와야 함

👉 매번 사용자가 요청을 할 때마다 드라이버를 로드하고 커넥션 객체를 생성연결하고 종료하므로 매우 비효율적

👉 이런 문제를 해결하기 위해서 커넥션 풀을 사용함

 


 

2. DBCP 데이터베이스 커넥션 풀이란?

 

- 커넥션 풀 DBCP의 개념

  • 웹 컨테이너 WAS가 실행되면서 일정량의 Connection 객체를 미리 만들어서 pool에 저장했다가,
    클라이언트 요청이 오면 Connection 객체를 빌려주고
    해당 객체의 임무가 완료되면 다시 Connection 객체를 반납 받아서
    pool에 저장하는 프로그래밍 기법

 


 

- 커넥션 풀 DBCP의 장점

  • 클라이언트가 빠르게 DB에 접속이 가능
    : DB 접속 설정 객체를 미리 만들어 연결하여 메모리 상에 등록해 놓기 때문에 불필요한 작업(커넥션 생성, 삭제)이 사라지므로
  • DB Connection 수를 제한할 수 있어서 과도한 접속으로 인한 서버 자원 고갈 방지가 가능함
  • DB 접속 모듈을 공통화하여 DB 서버의 환경이 바뀔 경우 쉬운 유지 보수가 가능함
  • 연결이 끝난 Connection을 재사용 👉 새로 객체를 만드는 비용을 줄일 수 있음

 


 

- 커넥션 풀 DBCP의 종류

  • commons-dbcp: 아파치에서 제공하는 대표적인 connection pool 라이브러리
  • tomcat-jdbc-pool: Tomcat에 내장되어 있으며, Apache Commons DBCP 라이브러리를 기반으로 만들어짐
  • HikariCP: 스프링 부트 2.0부터 default JDBC Connection Pool로 사용되며, zero-overhead의 특징을 가지고 있음
더보기

overhead: 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 및 메모리

 


 

- 커넥션 풀 DBCP의 유의사항

 

🖊️동시 접속자가 많을 경우

너무 많은 DB 접근이 발생할 경우에는 커넥션은 한정되어 있기 때문에 쓸 수 있는 커넥션이 반납될 때까지 기다려야 함

너무 많은 커넥션을 생성할 시에는 커넥션 또한 객체이므로 많은 메모리를 차지하게 되고, 프로그램의 성능을 떨어뜨리는 원인이 됨

👉 WAS에서 커넥션 풀을 크게 설정하면 메모리 소모가 큰 대신 사용자가 대기 시간이 줄어들고,
반대로 커넥션 풀을 작게 설정하면 그만큼 대기 시간이 길어짐

👉 사용량에 따라 적정량의 커넥션 객체를 생성해 두어야 함

 

🖊️Connection Pool이 커지면 성능은 무조건 좋아질까?

👉 No❗ Connection의 주체는 Thread이므로 Thread와 함께 고려해야 함

  • Thread Pool 크기 < Connection Pool 크기라면?
    : Thread Pool에서 트랜잭션을 처리하는 Thread가 사용하는 Connection 외에 남는 Connection은 실질적으로 메모리 공간만 차지하게 됨
  • Thread Pool 크기와 Connection Pool 모두 크기가 증가하면?
    - Thread 증가로 인해 더 많은 Context Switching이 발생함
    - Disk 경합 측면에서는 성능 한계가 발생함
    • 데이터베이스는 하드 디스크 하나 당 하나의 I/O를 처리하므로 블로킹이 발생함
    • 👉 특정 시점부터는 성능적인 증가가 Disk 병목으로 인해 미비해짐

👉 Connection은 Thread와 어느 정도 일치함

Connection이 많다는 의미는 데이터베이스 서버가 Thread를 많이 사용하는 것을 의미함

Context Switching으로 인한 오버헤드가 더 많이 발생하므로 Connection Pool을 아무리 늘리더라도 성능적인 한계가 존재

 


 

요약

  • JDBC는 자바 애플리케이션이 데이터베이스에 접근할 수 있도록 JAVA에서 제공하는 API
  • 하나의 JDBC로 어떤 DBMS든 각 벤더마다 제공되는 JDBC 드라이버를 통해 연결할 수 있음
  • 커넥션 풀이란 JDBC 실행 과정 중에서 생성되어야 할 Connection 객체를 미리 만들어서 pool이란 곳에서 저장을 해두는 기법
    • 장점: 불필요한 과정(Connection 객체를 생성, 삭제)을 줄여서 성능을 높일 수 있음
    • WAS에서 커넥션 풀을 크게 설정하면 메모리 크기가 큰 대신 사용자 대기 시간이 줄어듦
      반대로 커넥션 풀을 작게 설정하면 메모리 크기가 작은 대신 사용자 대기 시간이 길어짐
      👉 사용량에 따라 적정량의 커넥션 객체를 생성해두어야 함

 


 

출처

더보기

 

728x90