피드로 돌아가기
3 Asyncio Pitfalls That Took Me 3 Hours to Debug and Almost Crashed Production
Dev.toDev.to
Backend

Blocking Call 제거와 TaskGroup 도입을 통한 18초 응답 시간 획기적 단축

3 Asyncio Pitfalls That Took Me 3 Hours to Debug and Almost Crashed Production

BAOFUFAN2026년 5월 1일5intermediate

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 관리 복잡성 제거

원문 읽기