본문 바로가기

1.프로그래밍/DB

[DataSource] DataSource 설정 정리

728x90
반응형

해당 글은 Naver D2 를 읽고 참고하여 정리해 놓은 것입니다.

initialSize: BasicDataSource 클래스 생성 후 최초로 getConnection() 메서드를 호출할 때 커넥션 풀에 채워 넣을 커넥션 개수
maxActive: 동시에 사용할 수 있는 최대 커넥션 개수(기본값: 8)
maxIdle: 커넥션 풀에 반납할 때 최대로 유지될 수 있는 커넥션 개수(기본값: 8)
minIdle: 최소한으로 유지할 커넥션 개수(기본값: 0)

maxActive >= initialSize

maxActive = 10이고 initialSize = 20이라고 가정하면 최초에 커넥션을 생성할 때 initialSize 값이 최대 커넥션 개수인 maxActive 값보다 커서 논리적으로 오류가 있는 설정이다.

maxIdle >= minIdle

maxIdle < minIdle로 설정할 수는 있지만 최솟값이 최댓값보다 커서 논리적으로 오류가 있는 설정이다.

maxActive = maxIdle

maxActive 값과 maxIdle 값이 같은 것이 바람직하다.

maxActive = 10이고 maxIdle = 5라고 가정해 보자. 항상 커넥션을 동시에 5개는 사용하고 있는 상황에서 1개의 커넥션이 추가로 요청된다면 maxActive = 10이므로 1개의 추가 커넥션을 데이터베이스에 연결한 후 풀은 비즈니스 로직으로 커넥션을 전달한다. 이후 비즈니스 로직이 커넥션을 사용 후 풀에 반납할 경우, maxIdle=5에 영향을 받아 커넥션을 실제로 닫아버리므로, 일부 커넥션을 매번 생성했다 닫는 비용이 발생할 수 있다.

-> 동시에 최대 10개를 사용할 수 있는데, 최대 5개의 커넥션만 유지를 시켜야 한다.
-> 그런데 5개를 사용중에 하나의 요청이 더 들어오면 새로운 커넥션을 열고, 종료 후 닫아줘야 한다.
-> 그렇기에 매번 커넥션을 생성했다가 닫아주는 비용이 발생하게 된다.

initialSize와 maxActive, maxIdle, minIdle 항목을 동일한 값으로 통일해도 무방하다. 커넥션 개수와 관련된 가장 중요한 성능 요소는 일반적으로 커넥션의 최대 개수다. 4개 항목의 설정 값 차이는 성능을 좌우하는 중요 변수는 아니다.

커넥션을 얻기 전 대기 시간

BasicDataSource 클래스의 maxWait 속성은 커넥션 풀 안의 커넥션이 고갈됐을 때 커넥션 반납을 대기하는 시간(밀리초)이며 기본값은 무한정이다.

maxWait 속성을 적절하게 설정하지 않아도 일반적인 상황에서는 큰 문제가 되지 않는다. 하지만 사용자가 갑자기 급증하거나 DBMS에 장애가 발생했을 때 장애를 더욱 크게 확산시킬 수 있어 주의해야 한다.

maxWait 값도 사용자의 대기 가능한 시간 같은, 애플리케이션의 특성과 다른 주변의 설정, 자원의 상황 등을 고려해 판단해야 한다.

그렇다면 적당한 maxWait 값은 얼마일까? 이 부분을 이해하려면 Commons DBCP 외에 Tomcat의 동작 방식도 고려해야 한다. Tomcat은 스레드 기반으로 동작해 사용자의 요청을 처리한다. Commons DBCP가 커넥션 풀을 가지고 있는 것처럼 Tomcat도 내부에 스레드 풀(wait set)을 가지고 있어 사용자의 요청이 들어올 때마다 스레드 풀에서 하나씩 스레드를 꺼내 요청을 처리한다.

만약 갑작스럽게 사용자가 증가해 maxWait 값 안에 커넥션을 얻지 못하는 빈도가 늘어난다면 maxWait 값을 더 줄여서 시스템에서 사용하는 스레드가 한도에 도달하지 않도록 방어할 수 있다.

이런 상황이 자주 있다면 Commons DBCP의 maxActive 값과 Tomcat의 maxThread 값을 동시에 늘이는 것을 고려한다.

그러나 시스템 자원의 한도를 많이 넘는 요청이 있다면 설정을 어떻게 변해도 장애를 피할 수 없다.

애플리케이션 서버의 자원이 설정 변경을 수용할 만큼 충분하지 않다면 시스템을 확충해야 할 것이다.

DataSoucre Config

package com.springtour.hotel.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Slf4j
@Configuration
@ConfigurationProperties(prefix = "mysql")
public class DataSourceConfig {

    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private Integer maxIdle;
    private Integer maxTotal;
    private Integer initialSize;
    private Integer minIdle;

    @Bean
    public DataSource dataSource() {


        BasicDataSource basicDataSource = new BasicDataSource();

        basicDataSource.setDriverClassName(driverClassName);
        basicDataSource.setUrl(url);
        basicDataSource.setUsername(username);
        basicDataSource.setPassword(password);
        basicDataSource.setMaxIdle(maxIdle);
        basicDataSource.setMaxTotal(maxTotal);
        basicDataSource.setInitialSize(initialSize);
        basicDataSource.setMinIdle(minIdle);

        basicDataSource.setValidationQuery("SELECT 1");
        basicDataSource.setTestOnReturn(true);
        basicDataSource.setTestOnBorrow(true);
        basicDataSource.setTestWhileIdle(true);

        return basicDataSource;
    }

    /* Getter, Setter */
}

참고사항

DBCP 설정만 끝낸다고 될 문제가 아니라, Tomcat Thread Pool 또한 맞춰줘야한다.


https://techblog.woowahan.com/2663/


server.tomcat.thread.max=100
server.tomcat.thread.min-spare=100

  • 톰캣 서버의 스레드 풀 최댓값과 최솟값 설정
  • 최댓값과 최솟값은 동일하게 설정
  • 이 두 값이 다르면 서버에 부하가 높을 때는 최댓값까지 스레드가 생성되지만, 부하가 낮을 때는 최솟값까지 스레드가 줄어든다.
  • 런타임 도중 필요한 스레드를 생성하는 시간과 시스템 리소스 비용이 높기 때문에 두 값을 같게 사용할 때가 많다.
728x90
반응형