Post

커넥션풀과 데이터소스 이해




커넥션 반환

Connection pool

  • 커넥션 풀이란, 커넥션들을 여러 개 미리 갖고 있는 주머니다.
  • 디비 커넥션이 필요할 때 커넥션 풀에게 받아서 쓰는 용도이다.
  • 커넥션은 한 번 만들고 죽이는게 시간이 오래 걸려서 이게 더 효율적이다.


img-description 커넥션 받아오는 과정


  1. 드라이버에게 커넥션 요청
  2. 드라이버는 디비에게 TCP/IP 연결 후,
    • Id, Password 등 부가 정보를 전송한다.
    • 디비는 Id, Password로 내부 인증을 진행하고,
    • 내부에 DB 세션을 생성한다.
  3. 디비는 커넥션 생성이 완료됨을 알린다.
  4. 드라이버는 커넥션 객체를 생성하여 전송한다.

이러한 복잡한 과정을 매번 반복하면 리소스 낭비 + 응답 시간 지연 등이 일어나기 때문에 커넥션 풀에 미리 만들어 두고, 사용 후 반납하도록 한다. 반납된 커넥션 역시 없애버리는 것이 아니고, 잘 들고 있다가 다른 필요한 친구에게 빌려준다.


img-description 커넥션 풀에서 꺼내오는 과정


  1. 커넥션 풀은 처음 생성될 때 미리 커넥션을 정해진 수만큼 확보해 둔다.
  2. 드라이버에게 커넥션 요청을 한다.
  3. 드라이버는 커넥션 풀에게 요청하고, 커넥션 풀은 갖고 있던 커넥션 중에 하나를 빌려준다.
  4. 커넥션을 사용자에게 준다.
    • 커넥션 사용이 끝나면 다시 반납한다. (재사용 해야 하니까 close() 하지 않음)
    • 커넥션 풀 안의 커넥션들은 DB와 연결되어 있는 상태이기 때문에, 항상 통신이 가능하다.


  • 커넥션 풀의 커넥션 수는 시스템의 상황에 맞춰 개수를 정해두고 쓴다.
  • 최대 커넥션 수를 정할 수 있기 때문에, DB에 부담을 줄일 수 있다.
  • 여러 가지 오픈소스가 있지만, HikariCP를 주로 쓴다.





Datasource

  • A 커넥션 풀을 사용하다가 => B커넥션 풀로 변경했을 때,
  • 코드가 바뀌어야 한다. 이 의존성을 없애기 위해 커넥션 받아오는 방식을 추상화 하였는데,
  • 그 인터페이스가 javax.sql.Datasource이다.
  • 얘의 역할은 커넥션 조회 하나 뿐이다. getConnection();

  • 근데 DriverManager는 Datasource 인터페이스를 사용하지 않는다.
  • 커넥션을 매번 직접 만들어 사용하다가 커넥션 풀로 바꾼다거나 그 반대일 경우는,
    • 코드의 변경이 일어날 수 밖에 없다.
  • 스프링은 DirverManager를 통해서 Datasource를 사용할 수 있도록 DriverManagerDatasource라는 클래스를 제공한다.



DriverManager를 사용할 때

1
2
Connection connection1 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Connection connection2 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
  • 커넥션을 얻을 때 마다, 부가 정보를 넘겨줘야 한다.


DriverManagerDataSource를 사용할 때

1
2
3
4
DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);

Connection connection1 = dataSource.getConnection(URL, USERNAME, PASSWORD);
Connection connection2 = dataSource.getConnection(URL, USERNAME, PASSWORD);
  • 커넥션을 수백 번 요청해도, 부가 정보는 한 번만 넘겨주면 된다.


Connection Pool을 사용할 때

1
2
3
4
5
6
7
8
9
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaximumPoolSize(5);
dataSource.setPoolName("Babo");

useDatasource(dataSource);
Thread.sleep(1000); // 커넥션 풀에서 커넥션 생성 확인용
  • 커넥션 풀에서 커넥션을 만들 때는,
    • 애플리케이션의 실행 속도에 영향을 주지 않기 위해서 다른 쓰레드에서 동작한다.
  • 커넥션 만드는 로그가 찍히기도 전에 테스트가 끝나버리니까, 1초 슬립을 통해서 확인할 수 있다.

  • 만약 멕시멈 사이즈보다 많은 풀을 요구하면 어떻게 될까?
    • 멕시멈 사이즈가 5인데, 6번째 커넥션을 요구했다.
    • 다른 애들이 쓰고 돌려주기를 대기 시간 동안 기다린다.
      • 반납 시에 6번째 요구한 애한테 커넥션을 빌려준다.
      • 대기 시간이 넘을 경우. 타임아웃 예외를 날린다.





JdbcUtil을 이용해 리소스 정리

1
2
3
JdbcUtils.closeResultSet(resultSet);
JdbcUtils.closeStatement(statement);
JdbcUtils.closeConnection(connection);

JdbcUtil의 static 메서드로 리소스를 간단하게 정리할 수 있다. 만약 커넥션 풀을 사용중이라면 close 해버리지 않고 아니고 반납한다.





This post is licensed under CC BY 4.0 by the author.