-
DB 쓰려면 다음 같은 3단계로 표현 가능
-
- DB에 연결
-
- 쿼리 실행
-
- 사용 끝나면 연결 종료
-
-
네트워크 연결을 생성하는데 시간이 오래 걸릴수 있다. 이것이 전체 응답 시간에 큰 부분 차지하는 경우 존재.
-
매 요청마다 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 서버가 포화 상태에서 벗어나게 해야한다.
커넥션 대기 시간
대부분의 커넥션 풀은 대기 시간 세팅이 가능하다. 대기 시간이란 풀에 사용할 수 있는 커넥션이 없을 때 커넥션을 얻기 위해 기다릴 수 있는 최대 시간을 의미한다. 이걸 넘어서면 디비 연결 실패 에러가 뜬다.
대기하는 만큼 응답 시간도 당연히 길어진다. 참고로 히카리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 같은 것.
커넥션 풀이 제공하는 또다른 설정은 최대 유지 시간. 이 값이 4시간으로 설정되있으면 커넥션은 생성된 시점부터 최대 4시간까지만 유지됨. 4시간이 지나면 커넥션이 유효하더라도 커넥션 닫고 풀에서 제거된다.
메모 최대 유휴 시간과 최대 유지 시간을 무한대로 설정 않는게 좋다. 디비 설정을 보고 이와 맞추어 적절한 값을 지정해야된다.