db에서 connection pool을 사용한다는 이야기는 많이 들어보셨으리라 생각합니다. fastapi에서 db를 사용할 때, sqlalchemy를 많이 쓰곤 해요. 엔진을 초기화 할 때, 연결 풀링을 하기 위해 Queuepool과 같은 것을 많이 설정하는 편입니다. 그냥 Nullpool로 받을 때와, Queuepool과 같이 커넥션을 들고 있을 때 응답 속도가 유의미하게 차이가 난다. 라는 말은 많이 들으셨을 듯 한데요.

 

 이것은 실습으로 때워보도록 하겠습니다. 주의해야 할 점은 이 코드는 실습용으로 제작했다는 것입니다. 절대로 production에 적용하기 위해서 참고하지 말아주세요. 대신에 아. 이런 옵션이 있었구나와, connection pool이 어떤 역할을 하는 구나. 정도만 짚고 넘어가셔도 좋겠습니다.

 


 get /c/{c_id}는 id가 c_id인 유저를 얻어오는 서비스를 호출합니다. 그리고 ""를 떨굽니다.

 

 get_c_by_id도 그리 복잡하지 않습니다. 그냥 C라는 테이블에서 id가 c_id인 Row를 하나 리턴해서 가져옵니다.

 

 

 이제, get_db를 봅시다. db의 설정값들이 있는데요. StaticPool을 썼습니다. 문서를 보면, 정확하게 하나의 connection만을 pool하는 방식이라고 할 수 있어요. 그래도, size가 적은 것 뿐이지 커넥션 풀은 들고 있습니다. 서버 프로그램을 만들었으니, requests 모듈로 간단하게 응답 속도를 체크해 보겠습니다.

 

 BASE_URL은 127.0.0.1:8000입니다. 그리고 path가 c/{c_id}였으니 그대로 호출하면 되겠습니다. 

 

 다음, 15번 요청을 하고 응답을 받습니다. c_id를 1부터 3000까지의 random한 int를 뽑아 넘기는 것이 있는데요. 이는, C 테이블에 id가 1인 것부터 3000이 있는 것까지 있기 때문입니다. 요청을 하고 응답이 오기까지의 평균 시간을 측정해서 출력해 보겠습니다.

 

 

 14087326ns가 걸렸습니다.

 


이제, poolclass를 NullPool로 바꿔 보겠습니다.

 

 79539466ns가 걸렸습니다 초로 환산하면 0.08초입니다. 약 5배 가량이 더 걸린 것입니다. 문서를 보면 NullPool을 넘기는 경우, 풀을 사용하는 대신에 매 연결마다 connection을 열고 닫아버린다고 되어 있습니다.

 

 

 이를 도식화 하면 위와 같습니다. 매번 api가 날라갈 때 마다 connection을 열고 닫습니다. 이 비용이 0.06초로 상당히 큽니다. 제 프로젝트에서 db로 쓰고 있는 postgres에서는 pg_stat_activity라는 테이블을 보면, 이 현상을 확인할 수 있습니다.

 

 

 datname = 'fastapi' 라는 where 조건을 붙인 이유는 database가 fastapi인 컨넥션을 보기 위해서입니다. 여기서 주목해야 할 것은 backend_start와 xact_start, query_start, query입니다. query에 SELECT c.a, ... 가 나왔음을 볼 수 있는데요. 이는 제 fastapi에서 table c를 뒤지기 때문입니다.

 

 

 일정 시간이 흐른 후에 service 함수가 종료되게 하였습니다. 다음에 요청을 몇 회를 더 날릴 건데요. backend_start가 50분 18초로 업데이트 되었음을 볼 수 있어요. 이 backend_start가 왜 중요할까요? 문서에 따르면 이는 client와 server가 연결된 시간을 의미하기 때문입니다.

 

 이를 통해 알 수 있는 것은 매번 postgres와 fastapi의 연결이 새로 생성되어서 그 오버헤드가 매우 컸음을 의미해요. 기존에 연결된 아까운 connection이 재활용 되지 않았다는 것입니다.

 

 

 반면에, 이 경우는 PoolClass를 StaticPool로 설정해서 풀링을 설정한 것입니다. backend_start가 51분 6초에 시작되었습니다.

 

 그런데 이 수치가 그대로 유지되고 있습니다. xact_start와 query_start가 바뀌었음에도 backend_start는 그대로 유지되고 있단 말입니다. 이는 이미 db와 fastapi가 연결된 connection을 재활용 한다는 뜻입니다. 이미 수립된 저 연결을 fastapi에서 계속 쓰고 있다는 의미도 되겠습니다.