Python asyncio로 API 요청 병렬 처리 성능 개선
문제 상황
재택근무 전환 후 매일 아침 실행하는 데이터 수집 스크립트가 문제였다. 외부 API 3000개를 순차 호출하면서 평균 40분이 소요됐다.
# 기존 코드
for item_id in item_ids:
response = requests.get(f'https://api.example.com/items/{item_id}')
save_to_db(response.json())
asyncio + aiohttp 적용
Python 3.7부터 안정화된 asyncio를 활용해 비동기 처리로 전환했다.
import asyncio
import aiohttp
async def fetch_item(session, item_id):
try:
async with session.get(f'https://api.example.com/items/{item_id}') as response:
data = await response.json()
await save_to_db_async(data)
except Exception as e:
logger.error(f'Failed to fetch {item_id}: {e}')
async def main():
connector = aiohttp.TCPConnector(limit=50) # 동시 연결 제한
timeout = aiohttp.ClientTimeout(total=30)
async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
tasks = [fetch_item(session, item_id) for item_id in item_ids]
await asyncio.gather(*tasks, return_exceptions=True)
asyncio.run(main())
핵심 포인트
- TCPConnector limit: 서버 부하 방지를 위해 동시 연결 50개로 제한
- timeout 설정: 응답 없는 요청이 전체를 블로킹하지 않도록
- return_exceptions=True: 일부 실패가 전체를 중단시키지 않도록
결과
- 처리 시간: 40분 → 4분
- DB 연결 풀 조정 필요 (동시 쓰기 증가)
- 로깅 개선으로 실패 건 추적 용이
비동기 코드 디버깅이 까다로웠지만, 실행 시간 단축 효과가 확실했다.