IT

Python requests 재시도 로직 구현 시 단순 반복문보다 HTTPAdapter가 효율적인 이유

AI 자동화 실무 2026. 7. 21. 09:20
SMALL

Python의 requests 라이브러리를 사용할 때 네트워크 불안정성이나 일시적인 서버 오류에 대응하려면 urllib3의 Retry 클래스와 HTTPAdapter를 결합한 재시도 설계가 가장 효율적입니다. 단순히 에러가 났을 때 다시 호출하는 수준을 넘어, 서버에 가해지는 부담을 줄이면서도 성공 확률을 극대화하는 전략이 필요하기 때문입니다.

API 연동을 포함한 모든 네트워크 통신은 기본적으로 '실패할 수 있음'을 전제로 설계해야 합니다. 특히 마이크로서비스 아키텍처(MSA) 환경이나 외부 API 의존도가 높은 프로젝트라면, 일시적인 타임아웃이나 503 Service Unavailable 같은 오류로 인해 전체 프로세스가 중단되는 상황을 반드시 방지해야 합니다.

이 글을 읽기 전에 파이썬의 예외 처리와 기본적인 HTTP 통신 구조에 대해 먼저 이해하고 있다면 훨씬 수월하게 내용을 파악할 수 있습니다. 특히 API 에러 핸들링의 상위 개념인 '탄력적 설계(Resilience Design)'의 관점에서 재시도 로직을 바라보는 것이 중요합니다.

단순히 코드를 복사해서 붙여넣는 것이 아니라, 어떤 상황에서 재시도를 해야 하는지, 그리고 서버를 보호하기 위한 백오프(Backoff) 전략은 어떻게 세워야 하는지 실무적인 관점에서 정리해 보겠습니다.

Python requests 재시도 대표 이미지
Python requests 재시도 주제를 읽기 전에 먼저 보면 좋은 대표 이미지 · 핵심 포인트: 왜 필요한지, 재시도 기준, 백오프

핵심 내용 먼저 보기

핵심 키워드 Python requests 재시도 · 연관 검색어 Python requests 재시도, HTTPAdapter 사용법, urllib3 Retry 설정, 지수 백오프, API 재시도 전략

재시도가 필요한 에러와 무시해야 할 에러 구분하기

모든 에러에 대해 재시도를 수행하는 것은 자원 낭비일 뿐만 아니라 서버 상태를 악화시킬 수 있습니다. 재시도의 핵심은 '잠시 기다리면 해결될 가능성이 있는가?'를 판단하는 것입니다. 일반적으로 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout 같은 상태 코드는 서버가 일시적으로 과부하 상태이거나 배포 중일 때 발생하므로 재시도 대상에 포함됩니다.

반면 400 Bad Request, 401 Unauthorized, 404 Not Found 같은 에러는 클라이언트의 요청 자체가 잘못되었거나 권한이 없는 경우이므로 백 번을 다시 시도해도 결과는 같습니다. 실무에서는 status_forcelist 옵션을 통해 재시도할 상태 코드를 명확히 정의해야 하며, 보통 [500, 502, 503, 504]를 기본값으로 설정하는 경우가 많습니다.

지수 백오프(Exponential Backoff)로 서버 부하 방지하기

재시도를 설계할 때 흔히 하는 실수가 실패하자마자 즉시 다시 요청을 보내는 것입니다. 서버가 이미 과부하 상태라면 이러한 즉각적인 재시도는 불난 집에 부채질하는 격이 됩니다. 이때 필요한 것이 지수 백오프(Exponential Backoff) 전략입니다. 이는 재시도 횟수가 늘어날수록 대기 시간을 기하급수적으로 늘리는 방식입니다.

예를 들어 첫 번째 실패 후 1초, 두 번째는 2초, 세 번째는 4초를 기다리는 식입니다. urllib3의 Retry 클래스에서는 backoff_factor 설정을 통해 이를 간단히 구현할 수 있습니다. 이 설정 하나만으로도 클라이언트가 스스로 트래픽을 조절하여 서버가 회복할 시간을 벌어주는 성숙한 통신 로직을 완성할 수 있습니다.

POST 요청과 멱등성 문제 해결하기

GET 요청은 여러 번 수행해도 서버 상태가 변하지 않는 멱등성(Idempotency)을 가지지만, POST나 PATCH 요청은 다릅니다. 결제 요청이나 데이터 생성 요청이 타임아웃으로 실패했을 때, 실제로 서버에서는 처리가 완료되었는데 응답만 못 받은 상황일 수 있습니다. 이때 무작정 재시도를 하면 중복 결제나 중복 데이터 생성 문제가 발생합니다.

따라서 allowed_methods 옵션을 통해 재시도를 허용할 HTTP 메서드를 제한해야 합니다. 기본적으로 GET, PUT, DELETE 등은 안전하게 재시도할 수 있지만, POST 요청에 대해서는 서버 측에서 멱등성 키(Idempotency Key)를 지원하는지 확인한 후 신중하게 재시도 여부를 결정해야 합니다. 실무에서는 안전을 위해 POST를 재시도 대상에서 제외하는 것이 기본 설정인 경우가 많습니다.

HTTPAdapter를 활용한 세션 기반 재시도 구현

requests 라이브러리에서 재시도를 구현하는 가장 깔끔한 방법은 requests.Session() 객체에 HTTPAdapter를 마운트하는 것입니다. 이 방식을 사용하면 특정 도메인(Prefix)으로 나가는 모든 요청에 대해 일관된 재시도 규칙을 적용할 수 있어 코드 유지보수성이 비약적으로 향상됩니다.

단순히 max_retries에 숫자만 넣는 방식은 백오프나 상태 코드 필터링이 불가능하므로 지양해야 합니다. 대신 urllib3.util.retry.Retry 인스턴스를 직접 생성하여 세밀하게 제어하십시오. 이렇게 설정된 세션 객체는 애플리케이션 전반에서 재사용하며 네트워크 예외 상황에 대한 1차 방어선 역할을 수행하게 됩니다.

Python requests를 활용한 재시도 설계는 단순히 에러를 피하는 수단이 아니라, 서비스의 안정성을 결정짓는 중요한 요소입니다. 무분별한 재시도는 오히려 시스템 전체의 장애를 유발할 수 있으므로, 반드시 백오프 전략과 상태 코드 필터링을 병행해야 합니다.

실무에서는 재시도 횟수가 초과되었을 때 발생하는 MaxRetryError를 어떻게 로깅하고 모니터링할 것인지에 대한 고민도 함께 이루어져야 합니다. 반복적인 재시도 실패는 상위 시스템에 알람을 보내거나 서킷 브레이커(Circuit Breaker) 패턴으로 이어지는 트리거가 될 수 있기 때문입니다.

이 내용과 함께 읽어보면 좋은 주제로 'Python 로깅 라이브러리를 활용한 API 추적 방법'이나 '안전한 API 통신을 위한 타임아웃 설정 가이드'를 추천합니다. 네트워크 통신의 기본기를 탄탄히 다져두면 복잡한 분산 시스템에서도 흔들리지 않는 코드를 작성할 수 있을 것입니다.

자주 묻는 질문

재시도 횟수(max_retries)는 보통 몇 회가 적당한가요?

일반적으로 외부 API 통신의 경우 3회에서 5회 사이를 권장합니다. 너무 적으면 일시적인 장애에 대응하기 어렵고, 너무 많으면 전체 프로세스의 응답 시간이 지나치게 길어질 수 있습니다.

모든 500 에러에 대해 재시도를 해도 안전한가요?

서버 내부 로직 오류로 인한 500 에러는 재시도해도 해결되지 않을 가능성이 높습니다. 하지만 일시적인 인프라 장애와 구분하기 어렵기 때문에, 보통 500번대 에러는 재시도 대상에 포함하되 지수 백오프를 반드시 적용해야 합니다.

Timeout 설정과 Retry 설정 중 무엇이 우선인가요?

두 설정은 상호보완적입니다. Timeout은 개별 요청이 대기할 최대 시간을 결정하고, Retry는 그 요청이 실패했을 때 다시 시도할 횟수를 결정합니다. 따라서 Timeout을 먼저 적절하게 설정해야 Retry 로직이 의도한 대로 작동합니다.


해시태그

#Pythonrequests재시도 #HTTPAdapter사용법 #urllib3Retry설정 #지수백오프 #API재시도전략 #파이썬네트워크프로그래밍

LIST