DB 커넥션 풀 기본

  • DB 쓰려면 다음 같은 3단계로 표현 가능
      1. DB에 연결
      1. 쿼리 실행
      1. 사용 끝나면 연결 종료
  • 네트워크 연결을 생성하는데 시간이 오래 걸릴수 있음
    • 이것이 전체 응답 시간에 큰 부분 차지하는 경우 존재
  • 매 요청마다 DB 커넥션을 하려면 자원이 크게 듬
  • 이런 문제 해결위한 DB 커넥션 풀
    • DB에 연결된 커넥션을 미리 생성해서 보관
    • 애플리케이션은 DB 작업이 필요할 때 풀에서 커넥션 가져와 사용하고 반환
    • 커넥션 풀 쓰면 이미 연결된 커넥션을 재사용하기에 응답 시간 줄어드는 장점

  • 커넥션 풀의 다양한 설정 제공. 그중 중요한 설정
    • 커넥션 풀 크기(또는 최소 크기, 최대 크기)
    • 풀에 커넥션이 없을때 커넥션을 구할때까지 대기할 시간
    • 커넥션 유지 시간(최대 유휴 시간, 최대 유지 시간)

커넥션 풀 크기

  • 미리 생성해둘 커넥션 개수를 지정하는 설정
  • 이 커넥션 풀 크기가 커넥션 풀 설정에서 가장 중요
  • 서버는 주로 디비와 통신하기에 디비 연결을 관리하는 디비 커넥션 풀 크기를 잘못 설정하면 성능에 큰 영향을 줌
  • 다음과 같은 상황을 가정.
    • 커넥션 풀 크기는 '5'
    • 한 요청에서 쿼리를 실행하는데 1초 소요
    • 계산 용이를 위해 데이터 전송 시간 무시
    • 요청이 동시에 6개 들어오면 마지막 요청은 다른 요청이 커넥션 사용을 끝내고 풀에 반환할 때까지 대기 해야됨
  • 커넥션을 얻기위한 대기시간을 줄이려면 전체 응답 시간과 TPS를 고려해 커넥션 풀 크기를 지정해야함
    • 커넥션 풀 크기가 5이고 한 요청에서 쿼리 실행하는데 0.1 초가 걸린다 가정하자
    • 이때 1초에 처리할 수 있는 요청의 수는 50(1/0.1초 * 5)가 됨
    • 즉, 동시에 50개 요청이 와도 모두 1초 내에 끝난다
    • 물론 어떤 요청은 바로 커넥션 얻어 실행되고 어떤 요청은 커넥션 구하기위해 0.9초를 기다릴 수 있지만 여튼 모두 1초 안에 처리되는 것

  • 트래픽이 순간적으로 급증하는 패턴이라면 풀의 최소 크기를 최대 크기에 맞추는게 좋다
  • 트래픽이 점진적으로 증가시에는 DB연결 시간이 성능에 큰 영향 안주는 반면,
  • 트래픽이 급증할 경우 DB 연결 시간도 성능 저항의 주요 원인이 될 수도 있기 때문

  • 풀의 크기 늘리면 처리량은 당연히 늘어날 수 있다
  • 하지만 무식하게 늘리면 안된다
  • 만약 디비 서버의 CPU 사용률이 80%에 육박할때 늘리면 부하가 더 커져 쿼리 실행시간이 급격히 증가할 수도
  • 이런 상태에서는 풀의 크기 늘리기 보단 오히려 풀 크기 유지하거나 줄여서 DB 서버가 포화 상태에서 벗어나게 하자
  • 나) 그리고 DB가 동작중인 컴퓨팅 자원을 참고도 해야됨. 듀얼 코어일때 커넥션 풀을 100개 해봤자 일 할 수 있는건 2개뿐이다. 컨택스트 스위칭만 가중될껄?

커넥션 대기 시간

  • 대부분의 커넥션 풀은 대기 시간 세팅이 가능
  • 대기 시간이란 풀에 사용할 수 있는 커넥션이 없을 때 커넥션을 얻기 위해 기다릴 수 있는 최대 시간을 의미
  • 이걸 넘어서면 디비 연결 실패 에러가 뜬다
  • 대기하는 만큼 응답 시간도 당연히 길어진다
    • 참고로 히카리cp의 기본 대기시간은 30초
  • 따라서 응답시간이 중요한 서비스는 커넥션 대기 시간을 가능한 짧게 설정해야한다
  • 서비스 특성에 따라 다르지만 보통 0.5 ~ 3초 이내.

  • 대기시간을 짧게하면 풀이 모두 사용중일때 빠르게 '일시적 오류' 같은 에러 응답을 사용자에게 보여줄 수 있다
  • 대기 시간 때문에 오랜시간동안 무응답보단 빨리 에러를 반환하는게 나음
  • 커넥션을 얻지 못했을 때 빨리 에러 응답을 해야 서버의 부하가 증가하는것도 방지가 가능!
  • 예를 들어 풀 크기가 10이고 대기시간이 30초라 가정
    • 동시에 30개 요청이 발생했는데 순간적으로 DB 서버에 부하가 걸리면서 쿼리 실행시간이 10초로 늘었다
    • 이 시점에 각 요청은 다음 상태가 된다
      • 요청 10개는 풀에서 커넥션 확보하여 쿼리 실행을 시작
      • 요청 20개는 커넥션 확보 실패하여 대기 상태
    • 이때! 대기하는 사람 중 절반이 못기다리고 5초만에 요청을 취소한다면?
    • 먼저 확보한 10개의 요청은 쿼리 실행 시간 10초중 5초를 실행한 상태
    • 풀에서 커넥션 못 구한 요청 20개는 아직도 대기상태고 대기시간 30초중 5초가 흐름
    • 그리고 10명의 재요청이 있는데 이건또 대기를 새롭게 시작한다
    • 클라가 요청을 취소해도 서버는 일정 시간 동안 하던 작업을 중지 하지 않기에 이 시점 대기중인 요청의 수는 30개가 된다!
    • 대기중인 요청수가 20개에서 30개로 늘면서 서버가 동시에 처리해야될 요청이 30개에서 40개로 늘어났다
  • 이와 같이 몇 초 만에 요청을 취소하고 재요청이 반복되면 동시에 처리해야 할 요청 수는 계속 증가

  • 또 다른 가정으로 풀이 10개고 대기 시간이 1초라면?
  • 동일하게 30개 요청이 들어오고 20초가 지나고난 상태는 다음과 같다.
    • 커넥션 확보한 10개 요청은 쿼리를 2초동안 실행중
    • 확보못한 20개는 오류 응답을 받음
    • 이 시점 서버가 처리 중인 동시 요청 수는 10개
  • 이처럼 대기 시간 짧게 설정하면 서버 부하를 일정 수준으로 유지할 수 있으며 서버를 안정적으로 운영하는데 도움이 된다.

최대 유휴 시간, 유효성 검사, 최대 유지 시간

  • 요청이 없으면 커넥션풀도 사용되지 않는다. 이때 주의할 점이 있는데,
  • 커넥션이 사용되지 않는 시간이 길어지면 연결이 끊길 수 있다

  • MySQL 같은 디비는 일정 시간동안 클라와 상호작용이 없으면 자동으로 연결을 끊는 기능을 제공
  • 예를 들어 1시간동안 상호작용이 없다면 클라의 연결을 종료하도록 설정되어 있다 가정해보자
    • 새벽 시간대애 1시간 이상 사용자 없으면 커넥션 풀에 있는 모든 커넥션은 디비와의 연결이 끊어진다
    • 이때 디비와 연결이 끊긴 커넥션을 사용하면 에러가 발생

  • 이런 연결 끊김으로 발생하는 에러 방지위해 커넥션 풀은 다음 2가지 기능을 제공한다.
    • 최대 유휴 시간 지정
    • 유효성 검사 지원
  • 최대 유휴 시간 지정
    • 사용되지 않는 커넥션을 풀에 유지할 수 있는 최대시간 의미
    • 이걸 30분으로 세팅하면 30분 이상 사용되지 않는 커넥션은 종료되어 풀에서 제거
    • 이 시간을 디비에 설정된 비활성화 유지 시간보다 찗게하면, 디비가 연결 끊기 전에 풀에서 커넥션 제거 가능
    • "음... 커넥션 끊는(제거)를 디비가 관리안하고 커넥션풀(히카리CP)같은게 한다고 생각하면 되는걸까?"
  • 유효성 검사
    • 커넥션이 정상적으로 사용할 수 있는 상태인지 여부를 확인하는 절차
    • 풀의 구현 방식 따라 커넥션을 풀에서 가져올때 유효성을 검사하거나 주기적으로 검사 가능
    • 이 과정을 통해 연결이 유효하지 않은 커넥션을 식별하고 풀에서 제거할 수 있다
    • 유효성 검사를 위해 커넥션풀은 실제 쿼리를 실행하기도 한다
      • 예를 들어 SELECT 1 FROM dual, SELECT 1 같은 것

최대 유휴 시간과 최대 유지 시간을 무한대로 설정 않는게 좋다. 디비 설정을 보고 이와 맞추어 적절한 값을 지정해야된다.