WAS(Web Application Server)와 데이터베이스의 연결에는 많은 비용이 발생하는데, MySQL 8.0을 기준으로 했을 때 INSERT문 수행 시 필요한 비용의 비율은 다음과 같다.
이를 통해 알수 있듯, 서버가 DB에 연결하기 위해 Connect하는 비용이 가장 큰 비율을 차지한다. 따라서 DB 성능 향상을위해서는 Connection 비용을 줄일 필요가 있으며, 이를 위한 방법 중 하나가 Connection pool
이다.
커넥션 풀(Connection pool)
은 데이터베이스와 연결된 '커넥션'을 미리 만들어 놓고 이를 pool로 관리하는 것이다. 즉, 필요할 때마다 pool의 커넥션을 가져가 사용한 뒤, 작업이 완료되면 사용한 커넥션을 다시 pool에 반환하는 방식이다. 이처럼 미리 만들어 놓은 커넥션을 이용함으로써 커넥팅에 필요한 비용을 줄이고, DB 성능을 높일 수 있다.
또한 커넥션 풀을 이용할 경우 커넥션의 수를 제한할 수 있어 과도한 접속으로 인한 서버 자원의 고갈 등을 방지할 수 있으며, DB 접속 모듈을 공통화함으로써 DB 접속 환경이 바뀌더라도 유지 보수를 쉽게 할 수 있도록 한다.
커넥션 풀의 동작 과정은 다음과 같이 정리할 수 있다.
commons-dbcp
아파치에서 제공하는 대표적인 커넥션 풀 라이브러리이다.
상기 예시의 경우 최대 8개의 커넥션을 사용할 수 있으며, 4개는 사용 중이고 4개는 대기 중인 상태를 나타낸다.
각 속성이 나타내는 바는 다음과 같다.
속성 | 내용 |
---|---|
initialSize | BasicDataSource 클래스 생성 후 최초로 getConnection() 메서드 호출 시 커넥션 풀에 채워 넣을 커넥션의 개수 |
maxActive | 동시에 사용할 수 있는 최대 커넥션의 개수(default=8) |
maxIdle | 커넥션 풀에 반납할 때 최대로 유지될 수 있는 커넥션의 개수(default=8) |
minIdle | 최소한으로 유지할 커넥션의 개수(default=0) |
참고로 커넥션 개수와 관련된 속성은 다음과 같은 조건을 유지하도록 설정하는 것이 추천된다.
tomcat-jdbc-pool
HikariCP
HikariCP는 가벼운 용량과 빠른 속도를 갖는 JDBC의 커넥션 풀 프레임워크이다.
HikariCP는 커넥션 풀의 관리 방법에서 타 커넥션 풀 프레임워크와 차이가 있는데, 이를 통해 높은 성능을 확보한다. HikariCP는 커넥션 객체를 wrapping한 PoolEntry
로 커넥션을 관리하며, 이를 위해 ConcurrentBag이라는 구조체를 사용한다. 그리고 ConcurrentBag은 'HikariPool.getConnection() -> ConcurrentBag.borrow()'라는 메서드를 통해 사용 가능한 커넥션을 리턴하도록 되어 있어, 커넥션 생성을 요청한 스레드의 정보를 저장해 두고 이후 접근 시 저장된 정보를 이용해 빠르게 반환하는 것이다. 이러한 방법으로 속도 면에서 이점을 갖는다.
Thread가 커넥션을 요청했을 때 유휴 커넥션이 존재할 경우 해당 커넥션을 반환한다.
만약 유휴 커넥션이 존재하지 않을 경우 HandOffQueue를 polling하면서 다른 Thread가 커넥션을 반납하는 것을 기다린다. 그리고 다른 Thread가 커넥션 풀에 커넥션을반환하면 커넥션 풀은 HandOffQueue에 반납된 커넥션을 삽입하고, HandOffQueue를 polling하던 Thread는 커넥션을 획득하게 된다.
만약 커넥션 풀의 크기가 너무 작다면 커넥션을 획득하기 위해 대기하는 Thread가 많아지게 되며, 이는 커넥션 풀의 크기를 늘려 줌으로써 해결할 수 있다. 그렇다면 커넥션 풀이 클수록 좋은 것일까? 그렇지는 않다. 커넥션을 사용하는 주체인 Thread의 개수보다 커넥션 풀의 크기가 너무 클 경우 사용되지 않고 남는 커넥션이 생겨 메모리의 낭비가 발생하기 때문이다.
MySQL의 공식 레퍼런스에서는 600여 명의유저를 대응하는 데 15~20개의 커넥션 풀만으로도 충분하다고 언급하면서, 동시에 최대 연결 수를 무제한으로 설정한 뒤 부하 테스트를 진행하면서 최적화된 값을 찾는 것을 추천하고 있다.
또, HikariCP의 공식 문서에서는 다음과 같이 커넥션 풀 사이즈를 제안하고 있다.
connection = ((core_count * 2) + effective_spindle_count)이때 core_count는 CPU의 코어 수를, effective_spindle_count는 DB 서버가 동시 관리할 수 있는 IO의 개수를 의미한다.