본문 바로가기

컴퓨터

SQLAlchemy와 커넥션풀

참고: https://spoqa.github.io/2018/01/17/connection-pool-of-sqlalchemy.html

 

SQLAlchemy의 연결 풀링 이해하기

SQLAlchemy의 연결 풀 개념에 대해 이해하고 실전에서 만날 수 있는 이슈를 정리해보았습니다.

spoqa.github.io

https://rkd8527.tistory.com/25

 

커넥션이란 (커넥션 풀, 커넥션 고갈)

커넥션(Connection)이란?DB와 애플리케이션을 잇는 '통로'일반적으로 웹 애플리케이션은 요청을 받으면 데이터베이스(DB)에 정보를 조회하거나 변경한 뒤 그 결과를 반환한다. 이때 애플리케이션이

rkd8527.tistory.com

https://idea9329.tistory.com/832

 

RDS에서 "Aborted Connection" 메시지가 발생하는 이유와 해결 방법

Amazon RDS(MySQL, MariaDB, Aurora 등)를 사용할 때 "Aborted connection" 메시지가 발생하는 주요 원인은 클라이언트와 데이터베이스 간의 연결이 비정상적으로 종료되었기 때문입니다. 이 문제는 네트워

idea9329.tistory.com

 

0. 커넥션이란

커넥션(Connection)은 데이터베이스와 애플리케이션을 잇는 통로다.

커넥션을 생성하는 데에는 많은 비용이 든다.

네트워크 소켓을 열고, 인증(사용자명/비밀번호) 과정을 거치고, 데이터베이스와 핸드셰이크(대화 준비)하는 과정이 필요하다.

 

1. 커넥션풀이란

커넥션풀(Connection Pool)은 이후에 발생할 데이터베이스 작업 요청에 대비하여 데이터베이스 커넥션을 캐싱하는 기법이다. 데이터베이스 작업 요청이 빈번하게 발생할 때, 매번 커넥션을 생성하고 닫는 과정을 반복하면 이에 대한 비용이 크다(참고). 따라서 커넥션풀을 사용하여 커넥션 생성 과정을 줄일 수 있다. 짧은 요청이 빈번하게 발생하는 웹서비스와 같은 형태가 커넥션풀에 적합하다.

 

장점

- 성능 향상: 매번 커넥션을 생성하지 않고 재사용하므로, 데이터베이스 접근 속도가 빨라진다.

- 자원 관리 용이: 사용 가능한 커넥션 수를 한정하고 모니터링하기 쉽게 만들어 시스템 안정성을 높인다.

 

2. SQLAlchemy와 QueuePool

SQLAlchemy는 기본적인 커넥션풀로서 QueuePool을 제공한다. QueuePool은 설정된 pool_size와 max_overflow를 바탕으로 여러 커넥션으로 풀을 구성해서 운용한다. 프로젝트에서 사용한 MySQL이 QueuePool을 기본적인 커넥션풀로 이용하므로, QueuePool의 관리 방법을 중점적으로 다룬다.

 

3. QueuePool의 생애주기

1) 데이터베이스 작업 요청이 들어오기 전에는, QueuePool에도 커넥션은 없다.

2) 데이터베이스 작업 요청이 들어올 때, QueuePool에 유효 커넥션(쿼리를 수행하는 데 즉시 사용할 수 있는 커넥션)이 없으면 커넥션을 하나 생성한다.

3) 설정된 pool_size까지는, 데이터베이스 작업이 끝나서 더 이상 커넥션이 필요하지 않아도 커넥션을 닫지 않는다.

4) 데이터베이스 작업 요청이 들어올 때, pool_size까지 다 찼다 할지라도 유효 커넥션이 없으면 pool_size를 초과하여 임시로 커넥션을 하나 생성한다.

5) 4번 이후부터는 오버플로 상황이기 때문에, QueuePool은 데이터베이스 작업이 끝난 임시 커넥션을 닫아서 pool_size와 총 커넥션 수를 맞춘다.

6) QueuePool이 관리하는 커넥션이 pool_size + max_overflow까지 다 찬 상황에서 데이터베이스 작업 요청이 들어오면, 일단 일정한 시간동안 기다리게 한다(기본값은 30초). 풀 안에 남은 커넥션이 0이 되는 커넥션 고갈(Connection Exhaustion).

7) 일정한 시간동안 기다려도 QueuePool에 유효 커넥션이 없다면 TimeoutError 예외를 발생시킨다.

 

4. 적절한 QueuePool 설정값

서비스가 작을 때는 기본값이면 충분하지만, 서비스의 사용량이 많아진다면 설정을 현재 상황에 맞춰 바꿔주어야 한다.

 

pool_size: 현재 서비스에 평소의 데이터베이스 요청량이 들어올 때, 커넥션을 추가로 생성하지 않고 서비스를 유지할 수 있는 가장 작은 값(기본값 5)

- 너무 과하게 설정 시, 너무 많은 커넥션을 점유하고 있는 것이다. 커넥션을 유지하는 것 자체도 데이터베이스 서버의 메모리를 소모하는 것이기 때문에, 비효율적.

- 너무 적게 설정 시, 오버플로가 자주 발생하여 커넥션풀의 효과가 적어짐.

 

max_overflow: 현재 구성에서, 데이터베이스가 버틸 수 있는 최댓값(기본값 10)

- 너무 과하게 설정 시, 사용량이 폭증하면 데이터베이스의 한도 이상으로 커넥션을 생성하기에 데이터베이스가 버티지 못한다(DB의 max_connections 초과 에러: Too many connections).

- 너무 적게 설정 시 조금만 사용자가 더 유입되어도 커넥션 고갈에 따른 TimeoutError나 서비스 속도 저하를 자주 경험하게 된다.

 

따라서 서비스마다 내부에서 스트레스 테스트를 통한 벤치마킹으로 적정 값을 뽑아내는 것이 추천된다.

 

5. 유효하지 않은 커넥션 감지

네트워크, 타임아웃 설정, 애플리케이션 코드 문제 등 다양한 원인으로 인해, 클라이언트와 데이터베이스 간의 연결이 비정상적으로 종료될 수 있다.

이로 인해 'MySQL Server has gone away' 에러가 발생할 수 있다.

이를 방지하기 위해, 커넥션을 사용하기 전에 해당 커넥션이 'SELECT 1'과 같은 간단한 SQL 문을 사용하여 커넥션이 살아있는지 확인한다. 이는 'pool_pre_ping=True' 옵션으로 설정할 수 있다.

 

6. 웹 워커 수를 고려한 전체 커넥션 수

SQLAlchemy의 pool_size와 max_overflow는 애플리케이션 프로세스 1개를 기준으로 동작한다.

만약 컨테이너 수나 워커 수가 늘어난다면, 최대로 발생 가능한 DB 연결 수는 그에 비례해 늘어난다.

DB 서버의 허용 한도를 초과하지 않기 위해서는, 컨테이너 수와 워커 수를 고려하여 pool_size와 max_overflow 값을 설정해야 한다.

 

최대 발생 가능한 커넥션 수 = 서버(컨테이너) 수 * 워커 프로세스 수 * (pool_size + max_overflow)