[CS Study] Database - Connection pool

Frye 'de Bacon·2023년 12월 30일
0

Computer Science(CS)

목록 보기
38/40
post-thumbnail

Connection pool

커넥션 비용

WAS(Web Application Server)와 데이터베이스의 연결에는 많은 비용이 발생하는데, MySQL 8.0을 기준으로 했을 때 INSERT문 수행 시 필요한 비용의 비율은 다음과 같다.

  1. Coonnecting(30%)
  2. Sending query to server(20%)
  3. Parsing query(20%)
  4. Inserting row(10%)
  5. Inserting index(10%)
  6. Closing(10%)

이를 통해 알수 있듯, 서버가 DB에 연결하기 위해 Connect하는 비용이 가장 큰 비율을 차지한다. 따라서 DB 성능 향상을위해서는 Connection 비용을 줄일 필요가 있으며, 이를 위한 방법 중 하나가 Connection pool이다.

Connection pool

커넥션 풀(Connection pool)은 데이터베이스와 연결된 '커넥션'을 미리 만들어 놓고 이를 pool로 관리하는 것이다. 즉, 필요할 때마다 pool의 커넥션을 가져가 사용한 뒤, 작업이 완료되면 사용한 커넥션을 다시 pool에 반환하는 방식이다. 이처럼 미리 만들어 놓은 커넥션을 이용함으로써 커넥팅에 필요한 비용을 줄이고, DB 성능을 높일 수 있다.

또한 커넥션 풀을 이용할 경우 커넥션의 수를 제한할 수 있어 과도한 접속으로 인한 서버 자원의 고갈 등을 방지할 수 있으며, DB 접속 모듈을 공통화함으로써 DB 접속 환경이 바뀌더라도 유지 보수를 쉽게 할 수 있도록 한다.

커넥션 풀의 동작 과정은 다음과 같이 정리할 수 있다.

  1. HTTP로 커넥션 요청 발생
  2. 커넥션 풀에서 커넥션을 제공
  3. 커넥션을 사용
  4. 사용이 완료되면 커넥션을 다시 커넥션 풀에 반환

커넥션 풀의 종류

  1. commons-dbcp
    아파치에서 제공하는 대표적인 커넥션 풀 라이브러리이다.

    상기 예시의 경우 최대 8개의 커넥션을 사용할 수 있으며, 4개는 사용 중이고 4개는 대기 중인 상태를 나타낸다.

    각 속성이 나타내는 바는 다음과 같다.

    속성내용
    initialSizeBasicDataSource 클래스 생성 후 최초로 getConnection() 메서드 호출 시 커넥션 풀에 채워 넣을 커넥션의 개수
    maxActive동시에 사용할 수 있는 최대 커넥션의 개수(default=8)
    maxIdle커넥션 풀에 반납할 때 최대로 유지될 수 있는 커넥션의 개수(default=8)
    minIdle최소한으로 유지할 커넥션의 개수(default=0)

    참고로 커넥션 개수와 관련된 속성은 다음과 같은 조건을 유지하도록 설정하는 것이 추천된다.

    • maxActive >= initialSize
    • maxIdle >= minIdle
    • maxActive = maxIdle
  2. tomcat-jdbc-pool

    • tomcat에 내장되어 사용되는 커넥션 풀 라이브러리
    • Apache Commons DBCP 라이브러리를 바탕으로 만들어짐
    • Spring boot 2.0.0 하위 버전에서 사용하는 기본 DBCP
  3. HikariCP

    • Spring boot 2.0부터 기본으로 사용하는 JDBC connection pool
    • zero-overhead의 특징을 가짐
      ※ overhead : 어떤 작업을 처리하기 위해 사용되는 간접적인 처리 시간 및 메모리 등의 자원

HikariCP

개요

HikariCP는 가벼운 용량과 빠른 속도를 갖는 JDBC의 커넥션 풀 프레임워크이다.

HikariCP는 커넥션 풀의 관리 방법에서 타 커넥션 풀 프레임워크와 차이가 있는데, 이를 통해 높은 성능을 확보한다. HikariCP는 커넥션 객체를 wrapping한 PoolEntry로 커넥션을 관리하며, 이를 위해 ConcurrentBag이라는 구조체를 사용한다. 그리고 ConcurrentBag은 'HikariPool.getConnection() -> ConcurrentBag.borrow()'라는 메서드를 통해 사용 가능한 커넥션을 리턴하도록 되어 있어, 커넥션 생성을 요청한 스레드의 정보를 저장해 두고 이후 접근 시 저장된 정보를 이용해 빠르게 반환하는 것이다. 이러한 방법으로 속도 면에서 이점을 갖는다.

HikariCP의 동작 과정


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의 개수를 의미한다.


참고 자료

profile
AI, NLP, Data analysis로 나아가고자 하는 개발자 지망생

0개의 댓글