블로그로 돌아가기

낮은 성공률의 원인을 진단하는 방법

프록시 성공률은 모든 프로젝트의 중요한 지표입니다. 성능 저하의 원인을 파악하고 효율성을 회복하는 방법을 알아봅시다.

📅2025년 12월 3일

낮은 성공률의 원인을 진단하는 방법: 단계별 가이드

성공률(Success Rate)은 전체 시도 횟수 중 성공한 요청의 백분율입니다. 이 지표가 정상 범위 아래로 떨어지면 돈, 시간, 데이터가 낭비됩니다. 원인은 수십 가지가 될 수 있습니다: 잘못된 설정부터 대상 서버의 차단까지. 이 글에서는 체계적인 진단 방법을 살펴보고 해결책을 찾아보겠습니다.

성공률이란 무엇이고 정상 범위는 얼마인가

성공률(SR) = (성공한 요청 / 전체 요청 수) × 100%

정상 값은 작업 유형에 따라 다릅니다:

작업 정상 SR 위험 수준
공개 데이터 파싱 95–99% 85% 미만
SNS 자동화 90–97% 80% 미만
광고 검증 98–99.5% 95% 미만
API 통합 99–99.9% 98% 미만

기본 수준에서 SR이 5–10% 떨어지면 진단이 필요합니다. 20% 이상 떨어지면 긴급 조치가 필요합니다.

진단의 첫 단계

1단계: 로그 및 메트릭 확인

지난 24–72시간의 데이터를 수집하세요:

  • 정확히 언제 SR이 떨어졌나요? (정확한 시간)
  • 407 오류(프록시 인증 필요)를 반환하는 요청의 비율은?
  • 429 오류(너무 많은 요청)의 비율은?
  • 타임아웃(연결 타임아웃)의 비율은?
  • 부하(RPS - 초당 요청 수)가 변경되었나요?

2단계: 격리된 상태에서 테스트

애플리케이션 없이 프록시를 확인하는 간단한 스크립트를 사용하세요:

import requests
import time

proxy = "http://proxy_ip:port"
proxies = {"http": proxy, "https": proxy}
target_url = "https://httpbin.org/ip"

success = 0
failed = 0

for i in range(100):
    try:
        response = requests.get(
            target_url, 
            proxies=proxies, 
            timeout=10,
            verify=False
        )
        if response.status_code == 200:
            success += 1
            print(f"✓ 시도 {i+1}: 성공")
        else:
            failed += 1
            print(f"✗ 시도 {i+1}: 상태 {response.status_code}")
    except Exception as e:
        failed += 1
        print(f"✗ 시도 {i+1}: {str(e)}")
    time.sleep(0.5)

sr = (success / (success + failed)) * 100
print(f"\n성공률: {sr:.1f}%")
print(f"성공: {success}, 오류: {failed}")

이 테스트가 정상 SR을 보이면 문제는 코드나 설정에 있습니다. SR이 낮으면 프록시나 대상 서버에 문제가 있습니다.

프록시 측의 문제

오류 407: 프록시 인증 필요

원인:

  • 잘못된 자격증명(로그인/비밀번호)
  • 계정 만료
  • IP 주소가 화이트리스트에 없음(필요한 경우)
  • IP 로테이션이 작동하지 않거나 비활성화됨

해결책:

import requests

# 레지던셜 프록시의 올바른 형식
proxy = "http://login:password@proxy-host:port"
proxies = {"http": proxy, "https": proxy}

# 테스트
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.text)

프록시 서버 과부하

모든 서비스 사용자가 동시에 많은 요청을 보내면 RPS(초당 요청 수) 제한이 발생할 수 있습니다. 이는 드물지만 발생합니다.

확인하세요:

  • 현재 피크 RPS
  • 요금제의 제한
  • 로그에 429 오류가 있는지 여부

해결책: 요청 간 지연을 추가하거나 요금제를 업그레이드하세요.

IP 주소 품질

레지던셜 프록시의 경우 낮은 SR은 차단된 주소로 로테이션하고 있다는 의미일 수 있습니다. 확인하세요:

  • 403 Forbidden을 반환하는 IP 주소의 비율은?
  • 동일한 주소가 반복되나요?
  • 패턴이 있나요 - 한 국가/지역은 작동하고 다른 지역은 작동하지 않나요?

대상 서버의 차단 및 필터

오류 429: 너무 많은 요청

대상 서버가 하나의 IP에서 또는 전체적으로 너무 많은 요청을 감지했습니다. 해결책:

  • 지연 추가: `time.sleep(random.uniform(1, 3))`
  • IP 로테이션 사용: 각 요청마다 새 IP
  • RPS 감소: 병렬이 아닌 순차적으로 요청 전송
  • 현실적인 헤더 추가: User-Agent, Referer, Accept-Language

오류 403 Forbidden

서버가 IP(또는 프록시 IP)를 차단했습니다. 다음과 같을 수 있습니다:

  • 지리적 위치 필터
  • 프록시 서비스 블랙리스트
  • 봇 감지기(JavaScript, CAPTCHA)

해결책: 모바일 프록시 또는 로테이션이 있는 레지던셜 프록시를 사용하세요. 차단하기가 더 어렵습니다.

오류 403: User-Agent 확인

일부 서비스는 의심스러운 User-Agent를 거부합니다:

import requests
import random

user_agents = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
    "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15"
]

headers = {
    "User-Agent": random.choice(user_agents),
    "Accept-Language": "en-US,en;q=0.9",
    "Accept": "text/html,application/xhtml+xml",
    "Referer": "https://google.com"
}

response = requests.get(
    "https://target-site.com",
    headers=headers,
    proxies={"http": proxy, "https": proxy},
    timeout=10
)
print(response.status_code)

클라이언트 코드의 오류

잘못된 예외 처리

일반적인 오류: 코드가 연결 오류를 실패한 요청으로 계산하지만 재연결을 시도하지 않습니다:

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# 재시도 로직이 있는 올바른 방법
session = requests.Session()
retry_strategy = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=["GET", "POST"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)

try:
    response = session.get(url, proxies=proxies, timeout=10)
except requests.exceptions.RequestException as e:
    print(f"오류: {e}")
    # 로그하고 다음 요청으로 이동

잘못된 타임아웃

타임아웃이 너무 짧으면(1–2초) 느린 프록시가 거부됩니다:

  • 일반 파싱: 10–30초
  • 모바일 프록시: 15–45초
  • API: 5–10초

SSL/TLS 오류

`verify=False`를 사용하면 실제 문제를 숨길 수 있습니다. 인증서를 업데이트하는 것이 좋습니다:

import requests
import certifi

# 올바른 방법
response = requests.get(
    url,
    proxies=proxies,
    verify=certifi.where(),  # verify=False 대신
    timeout=15
)

네트워크 문제 및 타임아웃

연결 타임아웃 vs 읽기 타임아웃

차이가 중요합니다:

  • 연결 타임아웃: 프록시가 응답하지 않음(프록시 또는 네트워크 문제)
  • 읽기 타임아웃: 대상 서버가 데이터를 천천히 전송(대상 서버 문제)
import requests

# timeout = (connection_timeout, read_timeout)
try:
    response = requests.get(
        url,
        proxies=proxies,
        timeout=(5, 15)  # 연결 5초, 읽기 15초
    )
except requests.exceptions.ConnectTimeout:
    print("프록시가 응답하지 않음")
except requests.exceptions.ReadTimeout:
    print("대상 서버가 느림")

DNS 문제

대상 서버가 확인되지 않으면 프록시 오류가 아닙니다:

import socket

# 프록시 없이 DNS 확인
try:
    ip = socket.gethostbyname("target-site.com")
    print(f"확인됨: {ip}")
except socket.gaierror:
    print("DNS 오류 — 사이트를 찾을 수 없음")

낮은 SR 진단 체크리스트

  1. 기본 수준 설정: 이전에 정상이었던 SR은 얼마였나요?
  2. 격리된 테스트 실행 (위의 스크립트) 100개 요청
  3. 로그 확인: 어떤 HTTP 코드가 지배적인가요? (407, 429, 403, 타임아웃?)
  4. 407인 경우: 로그인/비밀번호 및 IP 화이트리스트 확인
  5. 429인 경우: 요청 간 지연 추가, IP 로테이션 사용
  6. 403인 경우: User-Agent, Referer 확인, 현실적인 헤더 추가
  7. 타임아웃인 경우: 타임아웃 증가, RPS 확인, 재시도 로직 사용
  8. 코드 확인: 올바른 예외 처리, 올바른 타임아웃
  9. 대상 서버 확인: 프록시 없이 접근 가능한가요?
  10. 다른 모든 것이 실패하면: 다른 프록시 유형이나 다른 제공자를 시도하세요

빠른 진단 테이블

HTTP 코드 가능한 원인 해결책
407 잘못된 프록시 자격증명 로그인/비밀번호, IP 화이트리스트 확인
429 너무 많은 요청 지연 추가, IP 로테이션 사용
403 IP 차단 또는 봇 감지 현실적인 헤더 추가, 모바일 프록시 사용
타임아웃 프록시가 느리거나 대상 서버 과부하 타임아웃 증가, RPS 확인
연결 거부 프록시 서버 접근 불가 IP:port 확인, 프록시 상태 확인

결론

낮은 성공률은 증상이지 질병이 아닙니다. 원인은 많을 수 있습니다: 코드의 오타부터 대상 서버의 차단까지. 체계적인 진단이 해결의 열쇠입니다:

  1. 메트릭 및 로그 확인
  2. 문제 격리(프록시 vs 대상 서버 vs 코드)
  3. 오류 유형 결정(407, 429, 403, 타임아웃)
  4. 해당 솔루션 적용

안정성과 높은 SR이 필요한 작업의 경우 IP 로테이션이 있는 레지던셜 프록시를 권장합니다. 감지하기가 더 어렵고 더 안정적입니다. proxycove.com에서 무료 테스트를 시도하고 작업에서 테스트해보세요.