Database Connection Pool

박건우·2022년 12월 30일
0
post-thumbnail

DBCP란 ?

클라이언트와 서버 사이드인 웹 어플리케이션에서 사용자의 요청에 따라 Connection이 생성된다면 수 많은 사용자의 요청이 들어왔을 때 서버에 과부하가 걸리게 된다. 이러한 상황을 예방하기 위해 미리 일정 갯수의 Connection을 생성해 Pool에 저장하고, 사용자의 요청이 발생하면 Connection을 제공하고 사용자와의 연결이 종료되면 Pool에 다시 반환해 보관 하는 것을 의미한다.

  • 여러 개의 DB Connection 객체를 생성한 뒤 Pool에 담아 놓고 필요할 때 불러와서 사용
  • 만약 Pool에 남은 Connection이 없다면 다른 Connection 객체가 Pool에 반환 될 때까지 클라이언트는 대기 상태로 전환
  • 사용이 끝난 Connection 객체는 다른 작업에서 다시 사용할 수 있도록 Pool에 반환

그렇다면 DBCP는 왜 필요한 걸까?

DB와 Connection을 맺는 작업은 매우 느리며 자원을 많이 소모하는 작업이다. 이러한 면에서 서버가 물리적으로 DB 서버에 연결되어 Connection을 맺는 작업은 당연히 비용이 클 수밖에 없는 것이다.

만약, 다수의 사용자들이 동시다발적으로 DB의 Connection 연결을 요청한다면 서버에 과부하가 일어날 수 있고, 최악의 경우에는 서버가 다운될 수도 있다.

따라서 이러한 큰 비용의 문제를 해결하기 위해 DBCP를 사용하는 것이 좋다.

DBCP 옵션 (Apache Commons DBCP 2.x 기준)

옵션설명기본 값
initialSize최초 커넥션을 맺을 때 Connection Pool에 생성되는 커넥션의 갯수0
maxTotal동시에 사용할 수 있는 최대 커넥션의 갯수8
maxIdleConnection Pool에 반납할 때 최대로 유지될 수 있는 커넥션의 갯수8
minIdleConnection Pool에 반납할 때 최소한으로 유지할 커넥션의 갯수0
maxWaitMillisPool이 예외를 throw하기 전 연결이 반환될 때까지 (사용 가능한 Connection 객체가 없는 경우) 대기하는 최대시간(ms)기본 값 X, -1 (무한정 대기)
validationQueryPool에 커넥션을 반환하기 전 풀의 연결을 확인하는데 사용할 SQL 쿼리로, 가장 간단한 쿼리를 사용하는 것이 좋다.
testOnBorrowPool에서 커넥션을 빌려오기 전 커넥션 객체의 유효성 검사를 실시할지 여부 → 객체의 유효성 검사에 실패하면 해당 커넥션은 Pool에서 삭제되고 다른 커넥션 객체를 빌려오는 것을 시도true
testOnReturn커넥션이 Pool로 반환 되기 전 객체의 유효성 검사 실시 여부false
testWhileIdleidle object evictor에서 객체의 유효성 검사 실시 여부 → 유효성 검사 실패 시 Pool에서 해당 커넥션 삭제false

maxTotal과 maxIdle

maxTotal과 maxIdle 값은 동일한 것이 좋다
동시에 사용할 수 있는 최대 커넥션 갯수(maxTotal)가 20이고, Pool에 반납할 때 최대로 유지 가능한 커넥션 갯수(maxIdle)가 10이라고 가정하자.

커넥션을 동시에 10개를 사용하고 있는 상황에서 1개의 커넥션이 추가로 요청된다면 maxTotal=20 이므로 1개의 추가 커넥션을 DB에 연결한 후 Pool은 비즈니스 로직으로 커넥션을 전달한다.

이후 비즈니스 로직이 커넥션을 사용한 후 Pool에 반납할 때, maxIdle=10 이므로 커넥션을 실제로 닫아버리기 때문에 일부 커넥션을 매번 생성했다 닫는 비용이 발생 할 수 있다.

DBCP 설정과 스프링 DB 연동 방식 (JAVA)

DBCP 설정

먼저 DBCP를 사용하기 위해선 DBCP 라이브러리를 다운로드 받아야 한다.
하지만, 우리는 Apache Maven의 종속성을 이용해 해당 라이브러리를 등록할 수 있다.

Maven은 아래와 같이 필요한 라이브러리를 pom.xml에 정의해 놓으면 네트워크를 통해 자동으로 다운로드 해준다.

그 다음, 데이터 소스(myBatis)와 관련된 설정 클래스를 하나 생성해줘야 한다.

아래는 MyBatisForOracleConfig 라는 이름으로 된 데이터 소스 관련 설정 클래스의 빈 메서드이다.

해당 메서드에서는 Apache Commons DBCP2 라이브러리에서 제공하는 BasicDataSource 클래스를 활용해 jdbc의 정보와 dbcp 옵션 값을 세팅하고 있다. 다시 말해 DB연동에 사용될 dataSource를 생성하는 하는 메서드이다.

메서드에 @Bean 어노테이션을 붙인 이유는 DB 연동을 처리하기 위해서 DB로부터 커넥션을 얻어야 하는데, DB정보를 빈으로 등록해 스프링 컨테이너가 생성하도록 해주기 위함이다.

DB연동이 된 상태라고 가정하고, 애플리케이션 구동 시 db 커넥션 요청이 발생할 때마다, 조금 더 정확히는 db 커넥션 객체를 Pool에서 빌려올 때(borrowObject)마다 dataSource에 유효성 검사 쿼리로 설정한 SELECT 1 FROM DUAL 구문이 동작하는 걸 Server console 창에서 확인할 수가 있다.

jdbc 정보는 아래와 같이 .properties 파일에 미리 작성된 값들을 특정 필드로 선언해 놓고 사용한다.



스프링 DB 연동 방식

위 메서드는 동일 클래스 내부에 선언된 또 다른 빈 메서드이다.

우리가 진행했던 대부분의 프로젝트는 myBatis 스프링 연동 모듈이기 때문에 SqlSessionFactoryBean을 활용해 데이터베이스를 연결하는 방식이 가장 일반적이다.
(RefreshableSqlSessionFactoryBean 의 경우, 서버 재구동 하지 않고도 xml의 변경된 내용이 반영된다.)

SqlSessionFactoryBean 또한 dataSource와 같이 여러 속성을 지정해줄 수 있다.

  • configLocation : xml 설정 파일 위치
  • mapperLocation : xml 파일들 위치
  • dataSource : dataSource 설정 객체

datasource를 생성하는 빈 메서드에서 생성 후 반환된 dataSource를 sqlSessionFactoryBean의 데이터소스 속성에 집어넣어 주는 형태로 짜여져 있다.
속성 지정이 완료되면, 애플리케이션 구동 시에 스프링은 지정해준 경로의 xml 설정 파일과 모든 xml 파일들을 로드하게 된다.

보기와 같이 특정 클래스에 @Configuration 어노테이션을 달아 놓고, 하나 이상의 @Bean 메서드를 내부에 선언하게 되면 Spring 컨테이너에 의해 빈 메서드가 정의되고 해당 서비스에 대한 요청이 가능해진다. → Spring 개념

추가로 myBatis 관련 설정 클래스이기 때문에 @MapperScan을 활용해 매퍼 인터페이스를 등록해준다.

@MapperScan 속성

  • basePackages : 스캔할 특정 패키지 명
  • sqlSessionFactoryRef : 스프링 컨텍스트에 둘 이상이 있는 경우, 사용할 SqlSessionFactory를 지정 (일반적으로 데이터 소스가 두 개 이상인 경우에만 필요)

후성의 경우 데이터 소스가 후성, sap, rdms (천안, 아산) 으로 4개가 필요하기 때문에 sqlSessionFactoryRef 속성을 활용해 데이터 소스를 구분 지은 것으로 보인다.


📌 뒤져본 곳들

0개의 댓글