Connection Pool이란,
JDBC 실행 과정 중에서 생성되어야 할 Connection 객체를 미리 만들어서 pool 이란 곳에서 저장을 해두는 기법이다.
JDBC 드라이버를 이용해서 데이터베이스 커넥션을 연결하는 과정은 복잡하다.
JDBC 드라이버는 데이터베이스와 TCP/IP 커넥션을 연결하고, 이 과정에서 3 way handshake 같은 네트워크 동작도 발생한다. 또한, TCP/IP 커넥션이 연결되면 Id와 Password 등 부가 정보를 데이터베이스에 전달하고, 인증이 완료되면 데이터베이스 내부에 세션을 생성한 뒤 완료 응답을 보낸다. 그리고 JDBC 드라이버는 클라이언트에게 커넥션 객체를 생성해서 반환해준다.
이 과정은 복잡하고 시간도 많이 소요되기 때문에 쿼리 요청마다 커넥션을 생성하면 응답도 느려지고 굉장히 비효율적이다.
그리고 이 문제를 해결하기 위해서 미리 커넥션을 생성해두고 꺼내 사용하는 방식인 커넥션 풀이 존재한다.
커넥션 풀은 애플리케이션이 시작하는 시점에 필요한 만큼 커넥션을 미리 확보해서 풀에 보관한다. (초기 생성도 원래처럼 JDBC 드라이버 이용)
커넥션풀에 들어있는 커넥션들은 TCP/IP로 데이터베이스와 연결되어 있는 상태이기 때문에 언제든지 SQL을 데이터베이스에 전달할 수 있게 된다.
이제 사용자 요청이 들어오면 JDBC 드라이버로 커넥션을 획득하는 것이 아니라 커넥션 풀을 통해 이미 생성되어 있는 커넥션을 객체 참조로 가져다 사용하고, 사용이 끝나면 종료하는 것이 아니라 다시 커넥션 풀로 반환해 준다.
만약 현재 사용 가능한 커넥션이 없다면 타임 아웃시간까지 대기하다가 예외를 던지게 된다. 이처럼 커넥션 풀은 서버 당 최대 커넥션 수를 제한할 수 있어서 무한정 연결이 생성되는 것을 막아주는 장점도 있다.
대표적인 커넥션 풀 오픈소스는 hikariCP, commons-dbcp2 등이 있다.
커넥션 풀의 장점은 불필요한 과정(Connection객체를 생성,삭제)을 줄여서 성능을 높일 수 있다.
WAS에서 커넥션 풀을 크게 설정하면 메모리 소모가 큰 대신 많은 사용자가 대기 시간이 줄어들고, 반대로 커넥션 풀을 적게 설정하면 그 만큼 대기 시간이 길어진다. 따라서 사용량에 따라 적정량의 커넥션(Connection)객체를 생성해두어야 한다.
🌟 추가 질문
📍 HikariCP?
HikariCP는 ThreadLocal을 사용하여 현재 스레드에서 사용한 커넥션을 추적한다. 이 방식은 커넥션 재사용을 빠르게 할 수 있게 해 주며, 성능을 최적화하는 데 중요한 역할을 한다.
스프링에서는 개발자가 직접 커넥션을 관리할 필요없이 자동화된 기법들을 제공하는데, SpringBoot 2.0 이전에는 tomcat-jdbc를 사용하다가 2.0이후 부터는 HikariCP를 기본옵션으로 채택 하고있다.
히카리 벤치마킹 페이지를 참고하면 성능이 월등한 것을 확인할 수 있다.

📍 Connection 최대 개수는 어떻게 설정하는 것이 좋을까?
만약 1분에 한번씩 30초 걸리는 요청이 들어올 경우, 커넥션은 하나만 있어도 가능할 것이다.
그렇다면 1분에 한번씩 70초가 걸리는 요청이라면? 요청을 바로 처리 하기 위해 2개로 늘릴 것이다. 하지만 하나의 커넥션은 50초 동안은 낭비가 될 것이다.
만약 24시간 중 1분만 사용자가 몰리는 애플리케이션이라면, 그 1분을 위해 max 커넥션을 늘릴 경우, 나머지 시간동안은 커넥션이 낭비가 될 수 있다.
무조건 max에 맞추기 보단, 어느 정도 사용자 경험을 보았을 때 너무 느려지지 않고 어느 정도 처리가 되는 선에서 커넥션을 잘 관리할 수 있어야 한다.
📍 Connection과 Thread 관계?
하나의 Thread에서 쿼리를 보내고 응답을 받을 수 있는 개수는 1개이다.
만약 Thread Pool의 Thread 개수가 50개인데, Connection의 개수는 100개라면 나머지 50개의 Connection은 어차피 대기하게 될 것이고 최대 50개만 사용이 될 것이다.
Connection은 Thread와 어느 정도 일치한다고 볼 수 있다.
Connection이 많다는 의미는 데이터베이스 서버가 Thread를 많이 사용한다는 것을 의미하고, 이에 따라 Context Switching으로 인한 오버헤드가 더 많이 발생하기 때문에 Connection Pool을 아무리 늘리더라도 성능적인 한계가 존재한다.
📍 DataSource란?
커넥션을 얻는 방법은 JDBC DriverManager를 직접 사용하거나 커넥션 풀을 사용 하는 등 다양한 방법이 존재한다. 하지만 각자 구현하는 방식은 다르고, 만약 커넥션을 얻는 방법을 변경한다면 코드도 수정을 해야 할 것이다.
하지만 스프링에서는 이 문제를 해결하기 위해, 커넥션을 획득하는 방법을 추상화 시켜 datasource라는 인터페이스를 제공한다. 개발자는 JDBC, HikariCP, commons-dbcp2 등 사용할 구현체를 선택하기만 하면 된다.