Python asyncio와 aiohttp로 API 동시 호출 최적화
문제 상황
외부 API를 호출해 데이터를 수집하는 배치 작업이 있었다. 순차 처리로 인해 5000건 처리에 약 2시간이 소요됐고, 이를 개선해야 했다.
기존 코드는 requests 라이브러리로 동기 호출을 반복하는 구조였다.
import requests
for item in items:
response = requests.get(f"https://api.example.com/data/{item.id}")
process_data(response.json())
해결 방법
aiohttp와 asyncio를 사용해 비동기 처리로 전환했다. 동시 요청 수를 제한하기 위해 Semaphore를 활용했다.
import asyncio
import aiohttp
async def fetch_data(session, item_id, semaphore):
async with semaphore:
async with session.get(f"https://api.example.com/data/{item_id}") as response:
return await response.json()
async def main(items):
semaphore = asyncio.Semaphore(50) # 동시 요청 50개 제한
async with aiohttp.ClientSession() as session:
tasks = [fetch_data(session, item.id, semaphore) for item in items]
results = await asyncio.gather(*tasks, return_exceptions=True)
return results
results = asyncio.run(main(items))
주의사항
- 연결 풀 관리: ClientSession은 재사용해야 한다. 매번 생성하면 오히려 느려진다.
- 에러 처리:
gather에return_exceptions=True를 설정해 일부 실패가 전체를 멈추지 않도록 했다. - Rate Limiting: Semaphore로 동시 요청을 제한해 서버 부하를 조절했다.
결과
처리 시간이 2시간에서 25분으로 단축됐다. 외부 API 응답 시간이 병목인 작업에서 비동기 처리는 확실한 효과가 있었다.