[HikariCP] Exception during pool initialization

Lee Yongin·2021년 10월 28일
1

배경지식

목록 보기
1/3

Connection Pool에 대해

App에 DBMS의 데이터를 주고싶을 때 그 사이 중개자 역할을 하는 것이 커넥션 풀(Connection Pool)이다.

위의 그림은 커넥션 풀의 원리를 간소하게 나타낸 그림이다.

Pool 속에 Database와의 connection을 미리 만들어 두고 Database에 접근 시 Pool에 남아 있는 connection 중 하나를 받아와서 사용한 뒤 반환하는 기법

커넥션 풀(Connection Pool)은 커넥션(Connection)을 풀(Pool)에 담아두었다가 요청이 들어오면
스레드가 커넥션을 요청하고, 풀에 있던 커넥션을 연결한다. 이로써 스레드 입장에서는 바로 쿼리를 날릴 수 있게 된다.
사용 후 반환된 연결은 즉시 닫히지 않고, 데이터베이스 커넥션 풀에 의해 관리 및 재활용되어 다음 대여에 대비하게 된다.
높은 동시성 요청으로 커넥션 풀 연결이 대여된 경우 다른 스레드는 커넥션 반환까지 기다리게 된다.

워터슬라이드 밑에 쌓인 튜브를 필요한 사람들이 사용한 후 계속 돌려놓고, 본인 차례를 기다리는 사람이 있기도 한 상황인 것이다.

Connection Pool 왜 사용할까

자원소모를 줄여 시스템 성능 향상


위의 그림처럼 App이 DBMS와 상호 작용할 때, 커넥션을 얻고 해제하는 과정이 시스템 리소스를 소비하는 주요 원인이다. 이런 과정을 자주 수행하면 시스템 성능에 큰 영향을 미칠 수 있다.
멀티스레딩 동시성이 큰 경우 시간이 많이 걸리는 데이터베이스 연결로 인해 시스템이 고착되기 때문이다. 드라이버와 DBMS 간의 TCP 연결을 만드는 데 드는 비용이 매우 많이 들고, 데이터베이스가 전달할 수 있는 동시 TCP 연결 수가 제한적이기 때문에, 데이터베이스 연결 풀이 나타나는데 시간이 걸린다.

그래서 Java는 아래 그림처럼 javax.sql 이라는 데이터소스 인터페이스를 공식적으로 지원한다고 한다. 이 인터페이스로 HikrariCP,DBCP, C3P0, DRUID 같이 시장에 있는 커넥션 풀 관리 툴에서 커넥션 객체를 가져올 수 있는 것이다.

위의 그림에서 번호대로 흐름을 읽어보면 이렇다.

  1. 사용자는javax.sql 인터페이스로 DataSource 개체의 getConnection() 메서드를 통해 연결을 받는다.
  2. 풀에 연결이 있는 경우 연결은 사용자에게 직접 반환된다.
  3. 풀에 연결이 없는 경우, 데이터베이스로부터 연결을 얻기 위해 Dirver 객체의 connect메소드가( Postgre, SQLite, MYSQL 등의 회사가 구현한 부분이라고 한다) 호출된다.
  4. 연결을 얻은 후(4,5) 연결 복사본을 풀에 넣은 다음(6,7) 발신자에게 연결을 반환할 수 있다.

풀에 연결이 없는 경우, 어쩔 수 없이 드라이버와 DBMS 간의 TCP/IP 통신으로 커넥션을 얻어야 하나보다. 하지만 다시 요청이 올 경우, 커넥션 풀이 이 커넥션을 해제하지 않고 다음 대여를 위해 풀 개체로 반환하고 재사용하게 된다. 이렇게 시스템 자원을 효율적으로 사용하는 것이 커넥션 풀의 장점..!이라고 이해했다.

After getting the connection, you can put a copy of the connection in the pool, and then return the connection to the caller. When the connection demander needs to connect again, it can be obtained from the pool and returned to the pool object after it is used up.

(이게 원문인데 제가 이해한 게 혹시 틀리다면... 댓글 부탁드립니다!)

커넥션의 세부사항 제어 가능

HikariCP의 깃허브에서 HikariCP 속성의 종류와 세부사항들을 볼 수 있다.

필수속성 활용

dataSourceClassName
jdbcUrl
username
password

필자의 프로젝트의 경우 spring boot의 applicatioin.properties 파일에서 위의 필수속성들을 확인할 수 있었다.

대충 에러로그 보고 히카리CP?..나니?? initialization?? 이거 뭐지? 이랬는데 뭔지 알 것 같아 좀 뿌듯하다

스크린 샷의 spring.datasource.url이 jdbcUrl 속성을 의미하고, dataSourceClassName은 jdbcUrl이 있다면 안 넣어도 되니 저 상태이다.

Note that you do not need this property if you are using jdbcUrl for "old-school" DriverManager-based JDBC driver configuration. Default: none
-dataSourceClassName 속성 설명 일부

그 외 세부속성 활용

이 상태에서 커넥션의 세부사항을 나머지 속성으로 제어할 수 있다.
필수속성 4개 외 속성 26개가 있지만 4가지 정도만 활용해보았다.(모두 디폴트 값으로 설정했다)

connectionTimeout이라는 속성은 클라이언트가 풀과의 연결을 기다리는 최대 시간(밀리초)을 제어한다. 커넥션을 사용 못할 때 이 시간을 초과하면 SQLException이 발생한다는데 내가 딱 그 모양이었던 것 같다.(장문의 에러메세지가 있는 포스팅 참고)

상관없다고 생각했던 에러 두 가지가 연관이 있었다....ㅎ

  1. Caused by: java.lang.IllegalArgumentException: Null value for 'password'
  2. org.postgresql.util.PSQLException: Something unusual has occurred to cause the driver to fail. Please report this exception.

어쨌든 이 위의 PSQLException이 발생한 이유는 password 속성값이 빠졌기 때문에 유저에게 커넥션을 주긴 커녕 데이터베이스에게 접근조차 못했기 때문에 시간초과SQLException이 발생한 것이었다.

더 공부하면 재미있는 내용이 많은 부분인 것 같다.

profile
f1을 좋아하는...🏆 f1처럼 빠르고 정확한 걸 좋아하는 안드로이드 개발자

0개의 댓글