FastAPI에서 비동기 DB 커넥션 풀 관리하기
문제 상황
사내 API 서버를 FastAPI로 전환하면서 PostgreSQL 연결에 asyncpg를 사용했다. 초기에는 문제가 없었지만 트래픽이 증가하자 TooManyConnectionsError가 발생하기 시작했다.
기존 코드는 요청마다 커넥션을 생성하고 있었다.
@app.get("/users/{user_id}")
async def get_user(user_id: int):
conn = await asyncpg.connect(DATABASE_URL)
user = await conn.fetchrow("SELECT * FROM users WHERE id = $1", user_id)
await conn.close()
return user
해결 방법
커넥션 풀을 애플리케이션 시작 시 생성하고 재사용하도록 변경했다.
from contextlib import asynccontextmanager
pool = None
@app.on_event("startup")
async def startup():
global pool
pool = await asyncpg.create_pool(
DATABASE_URL,
min_size=10,
max_size=20,
command_timeout=60
)
@app.on_event("shutdown")
async def shutdown():
await pool.close()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
async with pool.acquire() as conn:
user = await conn.fetchrow(
"SELECT * FROM users WHERE id = $1",
user_id
)
return user
결과
- 동시 요청 500개 기준 응답 시간이 평균 1.2초에서 0.3초로 개선
- DB 커넥션 에러 완전히 해결
min_size,max_size는 워크로드에 맞춰 조정이 필요했다
커넥션 풀 사이즈는 모니터링하면서 점진적으로 조정했다. pgBouncer 도입도 고려했지만 현재는 애플리케이션 레벨 풀링으로 충분했다.