피드로 돌아가기
Dev.toBackend
원문 읽기
Blocking Call 제거와 TaskGroup 도입을 통한 18초 응답 시간 획기적 단축
3 Asyncio Pitfalls That Took Me 3 Hours to Debug and Almost Crashed Production
AI 요약
Context
20개의 Downstream API를 순차적으로 호출하는 Data Aggregation 서비스의 I/O 병목 현상으로 인한 18초의 높은 지연 시간 발생. 단순 Asyncio 도입 시 Event Loop의 단일 스레드 특성과 동기 함수 간의 충돌로 인한 시스템 불안정성 노출.
Technical Solution
- Flask의 Thread Pool 환경 내 Event Loop 부재 해결을 위해 Async-native 프레임워크 전환 또는 Background Thread 기반 Queue 통신 구조 설계
- requests.get()과 같은 Blocking Call이 Event Loop를 점유하는 현상을 방지하기 위해 loop.run_in_executor()를 통한 Thread Pool 오프로딩 적용
- HTTP Client를 aiohttp로 전면 교체하여 Non-blocking I/O 기반의 완전한 Async 스택 구축
- 불완전한 Task 종료로 인한 Memory Leak 및 OOM(Out of Memory) 방지를 위해 asyncio.TaskGroup을 도입한 Task Lifecycle 자동 관리
- Downstream 서버 부하 방지 및 안정적 자원 제어를 위해 asyncio.Semaphore를 활용한 Concurrency Limit 설정
실천 포인트
1. Blocking 라이브러리(requests 등) 사용 시 loop.run_in_executor() 적용 여부 검토
2. Python
3.11+ 환경에서 Task 생명주기 관리를 위해 asyncio.TaskGroup 우선 고려
3. 무분별한 Task 생성 방지를 위해 Semaphore를 통한 동시성 제어 장치 마련
4. Async-native 프레임워크(FastAPI, Quart) 채택을 통한 Event Loop 관리 복잡성 제거