DB Connection Pool이란
DB Connection Pool이란?
DB Connection이란 DB를 사용하기 위해 DB와 애플리케이션 간 통신을 할 수 있는 수단입니다.
여기에 Pooling이라는 기법을 도입하려 DB Connection Pool이라고 부릅니다.
즉, 커넥션 풀은 데이터베이스와 연결된 커넥션을 미리 만들어 풀에서 관리하고, 필요시 이를 사용하고 반환하는 기법입니다.
위의 그림처럼 유저가 Web에 접속하게 되고 DB자원을 요청하게 되면 Connection Pool에 의해 관리되는 미리 생성된 5개의 Connection에서 사용 가능한 Connection을 사용하여 DB에 요청하게 됩니다.
DB Connection Pool을 사용하는 이유?
우선 DB에 query를 날리기위해서는 DB Connection이 필요합니다.
이때 실제 연산이나 쿼리 시간보다 DB에 연결하는 DB Connection 작업이 엄청난 비용이 듭니다.
비용이 많이 드는 작업같은경우 우리는 캐싱을 활용하여 그 작업을 저장해놓고 사용하는 경우를 떠올리시면 좋습니다.
즉, DB Connection Pool을 하나의 캐싱으로 이해해도 좋을 것 같습니다.
1. 연결 생성 시간 단축
위의 설명한 예시가 바로 연결 생성 시간을 단축한다는 의미입니다.
2. 제한된 리소스를 사용할 수 있음
만약 연결이 필요할 때마다 새로운 연결을 생성하면 과부화 상태일 때 새로운 생성이 요청되고 애플리케이션에 예측할 수 없는 동작이 발생할 수 있습니다.
이로써 일관된 DB 성능을 유지할 수 있습니다.
예를 들어 100개의 Connection Pool을 사용하면 100개의 제한된 리소스를 사용할 수 있습니다.
그러면 Connection Pool의 개수는 몇개를 해야 할까?
커넥션 풀이 무제한으로 많으면 좋은거 아닐까요?
WAS에서 Connection을 사용하는 주체는 Tread입니다.
따라서 Connection Pool의 개수는 Thread Pool의 크기보다 작아야 합니다.
만약 Connection Pool의 개수가 크다면 남는 커넥션 풀이 생겨서 메모리만 차지할 수 있습니다.
그러면 Thread Pool과 Connection Pool을 둘 다 늘리면 되는 거 아닌가요?
Thread Pool 또한 많이 사용한다고 좋은것이 아니라 Context Switching으로 인한 오버헤드가 발생할 수 있습니다.
반대로 너무 적은 Connection Pool의 크기를 사용하여 Connection을 획득하기 위해 대기하는 Thread가 많아지고, 이에 따라 성능적인 저하를 발생시킬 수 있습니다.
그러면 몇개가 적절할까요?
Hikari CP의 공식문서에 따르면 다음과 같은 공식을 추천하고 있습니다.
connections = ((core_count * 2) + effective_spindle_count)
core_count = Cpu 개수와 동일합니다.
core_count*2를 하는 이유?
Context Swtiching으로 인한 오버헤드를 고려하더라도 Disk의 I/O 혹은, DRAM이 처리하는 속도보다 CPU 속도가 월등히 빠르기 때문에 Thread가 Disk와 같은 작업에서 Blocking 되는 시간에 다른 Thread의 작업을 처리할 수 있는 여유가 생깁니다. 따라서 Hikari CP가 제시한 공식에서는 계수를 2로 선정하였습니다.
effective_spindle_count란?
하드 디스크는 하나의 spindle을 가지는데 spindle이란 DB 서버가 관리할 수 있는 동시 I/O 요청 수를 말합니다.
디스크가 16개 있는 경우에는 동시에 16개의 I/O를 처리할 수 있습니다.
따라서 해당 공식에서 디스크의 효율을 고려하여 spindle_count을 더해준 것 같습니다.
우아한 형제들 테크 블로그에서는 데드락을 방지하기 위해 아래와 같은 공식을 추천하고 있습니다.
Tn = 전체 Thread의 개수
Cm = 하나의 Task에서 동시에 필요한 Connection 수
MySQL의 Connection Pool에 대한 공식 문서에는 600명의 유저에 대응하는데 15~20개의 커넥션 풀만으로도 충분하다고 언급하고 있습니다.
또한 MySQL 공식문서에서는 최대 연결 수를 무제한으로 설정한 뒤 Apache JMeter 또는 The Grinder와 같은 도구를 사용하여 부하 테스트를 진행하면서 최적화된 값을 찾아나가는 것을 추천하고 있습니다.
HikariCP란?
HikariCP란 Spring의 기본 JDBC Connection Pool 프레임워크입니다.
spring-boot-starter-data-jap나 spring-boot-starter-jdbc를 의존할 경우 자동으로 HikariCP가 포함됩니다.
벤치마크를 보면 엄청난 최적화 속도를 보여주고 있습니다.
HikariCP 옵션
maximunPoolSize
최대 커넥션 개수를 설정하는 옵션입니다.
커넥션의 수와 1개의 커낵션의 초당 처리 요청 개수로 최대 TPS를 구해낼 수 있습니다.
단순한 TPS 계산식 = 1개의 커넥션의 초당 처리 요청 개수 * 동시 커넥션 개수
connectionTimeout
풀에서 커넥션을 구하기 위해 대기하는 시간을 설정할 수 있습니다.
기본값을 30초로 너무 크기 때문에 사용자는 응답 없는 상태로 30초를 기다려야 합니다.
따라서 기본값 대신에 0.5~3초 이내로 설정해서 빨리 에러 화면이라도 응답해주는 것이 좋습니다.
maxLifeTime
커넥션의 최대 유지 시간을 설정할 수 있습니다.
커넥션을 생상한 이후 이 시간이 지나면 커넥션을 닫고 풀에서 제거한 뒤 커넥션을 새로 생성합니다.
네트워크나 DB관련 설정값보다 큰 값을 사용하면 에러가 발생할 수 있기 때문에 네트워크나 DB 관련 설정 값보다 작은 값을 사용해야 합니다.
keppaliveTime
커넥션이 살아 있는지 확인하는 주기를 설정할 수 있습니다.
유효하지 않은 커넥션을 풀에서 제거하고 새로 생성합니다.
이 또한 네트워크타 DB의 관련 설정 값보다 작은 값을 사용합니다.
minimumIdle
최소 유휴 커넥션 개수를 설정할 수 있습니다.
설정하지 않으면 maximumPoolSize와 동일하며 Hikari 문서에서는 이를 설정하지 않는 것을 추천합니다.
만약 이 값을 작게 설정하게 되면 트래픽이 특정 시점에 급격히 증가할 때 성능 저하를 일으킬 가능성이 있습니다.
idleTimeout
사용되지 않고 풀에 머무를 수 있는 시간을 설정할 수 있습니다.
출처
https://kafcamus.tistory.com/47?category=916723
https://hyuntaeknote.tistory.com/12
https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
https://techblog.woowahan.com/2663/
https://www.youtube.com/watch?v=6Q7iRTb4tQE