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))

주의사항

  1. 연결 풀 관리: ClientSession은 재사용해야 한다. 매번 생성하면 오히려 느려진다.
  2. 에러 처리: gatherreturn_exceptions=True를 설정해 일부 실패가 전체를 멈추지 않도록 했다.
  3. Rate Limiting: Semaphore로 동시 요청을 제한해 서버 부하를 조절했다.

결과

처리 시간이 2시간에서 25분으로 단축됐다. 외부 API 응답 시간이 병목인 작업에서 비동기 처리는 확실한 효과가 있었다.