Python 비동기 HTTP 요청 병렬 처리로 API 응답 속도 개선
문제 상황
매일 새벽 실행되는 배치 작업에서 외부 결제 API를 호출해 결제 상태를 동기화하는 로직이 있었다. 최근 거래량이 늘면서 API 호출 횟수가 50~100건으로 증가했고, 순차 처리 방식 때문에 배치 실행 시간이 30초를 넘어가기 시작했다.
기존 코드는 requests 라이브러리로 동기 방식으로 작성되어 있었다.
import requests
def sync_payment_status(payment_ids):
results = []
for pid in payment_ids:
response = requests.get(f'https://api.payment.com/status/{pid}')
results.append(response.json())
return results
해결 방법
aiohttp와 asyncio를 사용해 비동기 병렬 처리로 전환했다.
import asyncio
import aiohttp
async def fetch_status(session, payment_id):
async with session.get(f'https://api.payment.com/status/{payment_id}') as response:
return await response.json()
async def async_payment_status(payment_ids):
async with aiohttp.ClientSession() as session:
tasks = [fetch_status(session, pid) for pid in payment_ids]
results = await asyncio.gather(*tasks)
return results
# 실행
results = asyncio.run(async_payment_status(payment_ids))
결과
50건 기준으로 순차 처리는 약 25초, 비동기 처리는 약 3초로 개선되었다. API 서버가 동시 요청을 처리할 수 있는 상황이라면 비동기 처리가 확실히 효과적이었다.
다만 동시 요청 수 제한이 필요한 경우 asyncio.Semaphore를 사용해 제어할 수 있다.
sem = asyncio.Semaphore(10) # 최대 10개 동시 요청
async def fetch_with_limit(session, payment_id):
async with sem:
return await fetch_status(session, payment_id)
재택 근무 중 로컬에서 테스트하기 좋았던 케이스였다. 배치 작업 최적화는 당장 체감되는 부분은 아니지만, 장기적으로 서버 리소스 절약에 도움이 된다.