Python 비동기 처리 asyncio로 API 응답 속도 개선
문제 상황
외부 API 10개를 순차적으로 호출하는 크롤러가 있었다. 각 API 응답 시간이 평균 2초라 전체 처리에 20초 이상 소요됐다. requests 라이브러리를 사용한 동기 처리 방식의 한계였다.
asyncio 도입
Python 3.7부터 asyncio가 안정화되면서 본격적으로 사용할 수 있게 됐다. aiohttp를 사용해 비동기 HTTP 요청으로 전환했다.
import asyncio
import aiohttp
async def fetch_data(session, url):
async with session.get(url) as response:
return await response.json()
async def main():
urls = ['http://api1.com', 'http://api2.com', ...]
async with aiohttp.ClientSession() as session:
tasks = [fetch_data(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
loop = asyncio.get_event_loop()
data = loop.run_until_complete(main())
마주친 이슈
- DB 커넥션 풀 문제: 기존 psycopg2는 비동기를 지원하지 않아 aiopg로 교체했다.
- 타임아웃 처리: asyncio.wait_for()로 개별 요청에 타임아웃을 설정했다.
- 에러 핸들링: gather()에 return_exceptions=True 옵션을 줘서 일부 실패해도 전체가 중단되지 않게 했다.
결과
평균 응답 시간이 20초에서 5초로 단축됐다. API 호출이 병렬로 처리되면서 가장 느린 요청의 응답 시간만큼만 걸리게 됐다. CPU 사용률도 크게 증가하지 않아 서버 리소스 측면에서도 효율적이었다.
다만 코드 복잡도가 올라가고 디버깅이 어려워진 부분은 트레이드오프다. 성능이 중요한 구간에만 선택적으로 적용하는 게 맞다고 판단했다.