데이터베이스 커넥션 풀과 HikariCP

크리링·2023년 4월 7일
0
post-thumbnail

데이터베이스 커넥션

우리가 개발하는 WAS와 DB는 서로 다른 시스템이다. 따라서 DB 드라이버를 사용하여 DB에 연결해야 한다.



DB 연결 생애 주기

  1. DB 드라이버를 사용하여 DB 연결 열기
  2. 데이터를 읽고 쓰기 위해 TCP 소켓 열기
  3. TCP 소켓을 사용하여 데이터 통신
  4. DB 연결 닫기
  5. TCP 소켓 닫기





DB 커넥션 풀

사용자로부터 요청이 올 때마다 DB 연결을 수립하고 해제 비효율적
-> 미리 여러개의 DB 커넥션을 생성해놓고, 필요할 때마다 꺼내쓰는 방법 데이터베이스 커넥션 풀

DB 커넥션 풀을 사용하면 DB 요청이 들어올 때마다 DB 연결을 수립하고, 통신한 뒤, 닫는 과정을 거치지 않는다. DB 커넥션 풀에는 사전에 DB와 이미 연결이 수립된 다수의 커넥션들이 존재한다. 커넥션 풀 안의 커넥션들은 DB 요청이 들어올 때마다 새롭게 연결을 수립하고 닫는 대신 항상 연결을 열린 상태로 유지한다.

WAS는 DB 커넥션이 필요할 때 직접 커넥션을 생성하지 않고, 커넥션 풀 컨테이너로부터 커넥션을 하나 건네받고, 사용을 마치면 반납한다. 이렇게 DB 연결을 열고 닫는 비용을 절약한다.






HikariCP

가장 많이 사용되는 DB 커넥션 풀 프레임워크
스프링부트에 기본으로 내장되어 있는 JDBC DB 커넥션 풀링 프레임워크



성능이 압도적으로 우수

HikariCP 팀에서 제공한 데이터페이스 커넥션 풀링 프레임워크들의 벤치마크 결과



적정 DB 커넥션 풀 사이즈

HikariCP 공식

공식문서에서의 커넥션 풀 사이즈 제안

connection = ((core_count * 2) + effective_spindle_coount)
  • core_count는 CPU의 코어수
  • effective_spindle_count는 DB서버가 동시 관리할 수 있는 IO 개수



HikariCP deadlock

DBCP를 사용할 때 교착 상태(deadlock)를 주의해야 한다.
교착상태란 쓰레드가 서로의 DB connection이 반납되기만을 무한정 대기하는 상황

deadlock 시나리오

  1. Thread-1이 작업을 수행하기 위해 2개의 DB Connection이 필요하다.
  2. DBCP의 사이즈는 1이다. (total = 1, active = 0, idle = 1, waiting = 0)
  3. Thread-1이 작업을 수행하기 위해 DBCP로부터 커넥션을 받아온다.
  4. DBCP에 현재 존재하는 커넥션은 1개이므로, 1개만 Thread-1에게 건네준다.
  5. Thread-1은 1개의 커넥션으로는 작업을 수행할 수 없으므로 다른 쓰레드로부터 1개의 커넥션이 반납될동안 기다린다.
  6. 하지만 DBCP의 상태는 total = 1, active = 1, idle = 0, waiting = 0 이므로 반납될 커넥션이 존재하지 않는다. 즉, Thread-1은 자기자신이 커넥션을 반납하는 것을 기다리는 상황이다. 즉, 데드락을 의미한다.

해결

이 문제를 해결하기 위해서 HikariCP 팀은 아래와 같은 DBCP 최소 사이즈 공식을 제안한다.

  • Tn은 WAS의 전체 쓰레드 개수
  • Cm은 쓰레드가 작업을 수행하기 위해 동시에 필요한 DB Connection의 개수

위 공식을 적용해보자. 만약 쓰레드 최대 개수가 10개고, 동시에 필요한 커넥션수가 3개라고 해보자. 위 공식에 대입해서 계산해보면, 21이라는 결과가 나온다. 10개의 쓰레드에 모두 2개씩 커넥션을 할당하면, 1개의 커넥션이 풀에 남는다. 즉, 최소한 하나의 쓰레드는 무조건 커넥션을 3개 확보하고 작업을 처리하고, 커넥션을 반납할 수 있다. 따라서 데드락이 발생하지 않는다.

위 공식의 결과값은 어디까지나 데드락이 발생하지 않을 최소값이다. 따라서 공식 결과값에 +α가 필요하다.

그런데 그냥 DBCP 사이즈를 무식하게 크게 설정하면 데드락이고 뭐고 문제가 발생하지 않을 것 같다. 하지만 무제한으로 DB 커넥션 풀의 커넥션 개수를 늘릴 수는 없다. 커넥션도 결국 객체이기 때문에 메모리 공간을 차지하기 때문이다. 따라서 커넥션 개수와 메모리는 trade-off 관계이다. 따라서 위 공식에서 α 값을 성능 테스트를 통해 최적의 값을 찾아내야 한다.






출처 및 참고 : 데이터베이스 커넥션 풀 (Connection Pool)과 HikariCP,
Spring DB커넥션풀과 Hikari CP 알아보기,
HikariCP Dead lock에서 벗어나기 (이론편) | 우아한형제들 기술블로그
HikariCP Dead lock에서 벗어나기 (실전편) | 우아한형제들 기술블로그

0개의 댓글