KYC 없이 — 신분증, 셀카, 문서 없이. 암호화폐로 결제: BTC, USDT, USDC, ETH, SOL, LTC
언어: 한국어
시작하기

문서 · 동시성 · 처리량 · 예의

레지덴셜 프록시를 통한 동시성 및 처리량

게이트웨이는 스레드가 아니라 GB당 과금하므로 실제 제한은 각 대상 사이트별입니다. 필요한 처리량에 맞게 동시성을 설정하고, 호스트별로 제한을 두고, 응답에 따라 속도를 조절하세요.

마지막 업데이트: · 5 분 읽기

빠른 답변

레지덴셜 프록시로 몇 개의 동시 요청을 실행할 수 있나요?

대상마다 허용 가능한 만큼: CrawlRelay은 스레드나 연결이 아닌 GB당 레지덴셜 트래픽을 과금합니다(US$0.50/GB은 50 GB부터). Little 법칙으로 동시성 크기를 정하세요. 진행 중 요청 수 = 페이지당 초 × 초당 페이지 수, 그런 다음 호스트별 2~4개로 제한을 두고 429 또는 503 응답이 나타나면 줄이세요. 결제는 KYC 없이 암호화폐로 됩니다.

동시성 한눈에 보기

과금트래픽 GB당 과금; 스레드 및 연결은 과금하지 않음
크기 산정 규칙진행 중 요청 수 = 처리량 × 대기 시간 (Little 법칙)
호스트별 시작점동시 요청 2–4개; 작은 사이트는 1개 요청 후 지연
속도 늦춰야 할 신호429, 503, 증가하는 응답 시간, 챌린지 페이지
대역폭 계산법초당 페이지 수 × 페이지당 바이트 × 3,600 = 시간당 바이트
레지덴셜 중간 응답 시간프록시 네트워크에서 0.93초, 실제 대상에서 3.21초 (Proxyway 2026)

필요한 처리량에서 동시성을 어떻게 산정하나요?

Little 법칙을 사용하세요: 진행 중인 요청 수는 원하는 처리율에 각 요청에 걸리는 시간을 곱한 값과 같습니다. Proxyway의 Proxy Market Research 2026에 따르면 실제 사이트 대상의 레지덴셜 프록시 요청 평균 시간이 3.21초였으니, 네트워크 단독의 1초 미만 수치가 아닌 실제 사이트 기준 2~4초로 계획하세요.

목표요청 당 시간진행 중 요청 수
초당 5 페이지2초10
초당 20 페이지2초40
초당 20 페이지4초80
초당 100 페이지3초300

그 요청들을 여러 호스트에 분산하세요. 200개 사이트에 걸쳐 진행 중인 40개 요청은 원만하지만, 하나의 작은 사이트에 40개 요청은 동의하지 않은 부하 테스트입니다.

그 처리량은 대역폭을 얼마나 사용하나요?

초당 페이지 수에 페이지당 바이트를 곱하세요. 초당 20개의 HTML 페이지와 페이지당 50KB로 크롤링하면 초당 1MB, 즉 시간당 3.6GB, 하루 약 86GB가 됩니다. 렌더링 페이지당 2MB라면 동일한 비율로 초당 40MB가 됩니다.

결과에 요금제의 GB당 가격 US$0.50/GB (50GB 이상 CrawlRelay)를 곱해 시간당 비용을 계산하세요. 대역폭 계산기 가이드에서는 페이지 유형별 평균 페이지 무게를 제공합니다.

호스트당 어떤 제한을 시작해야 하나요?

대상호스트당 병렬 요청 수요청 사이 지연비고
작은 사이트 (블로그, 지역 상점)12–5초robots.txt에 Crawl-delay가 있다면 준수
중간 규모 사이트2–40.5–2초응답 시간을 확인하고 두 배로 늘어나면 속도를 줄이세요
CDN이 포함된 대형 플랫폼4–16AutoThrottle 또는 적응형429 및 5xx 응답 비율이 안정적일 때만 증가
공용 API문서화된 제한문서대로제공자가 주는 API 키와 제한을 사용하세요

동시성을 자동으로 조절하려면 어떻게 하나요?

TCP 혼잡 제어 규칙을 사용해 가감법을 적용하세요: 정상 응답이 연속되면 슬롯을 하나씩 추가하고 429 또는 503 응답 시 제한을 절반으로 줄입니다. 아래 제한기는 각 호스트별 제한을 관리하고 해당 호스트로의 요청을 Retry-After 지연 후 일시 중지하며, 한 번 재시도하고 설정한 최대 한도를 초과하지 않습니다. 네트워크 오류는 값으로 반환되어 한 번의 타임아웃이 배치를 중단하지 않습니다.

Python asyncio: httpx와 함께 사용하는 적응형 제한
import asyncio
import random
from urllib.parse import urlsplit

import httpx

PROXY = "http://USERNAME-country-us:[email protected]:7777"


class AdaptiveLimit:
    """One per host: +1 slot after 20 clean responses, halve on 429/503, pause for Retry-After."""

    def __init__(self, start=2, low=1, high=16):
        self.limit, self.low, self.high = start, low, high
        self.in_flight, self.clean = 0, 0
        self.pause_until = 0.0
        self.cond = asyncio.Condition()

    async def __aenter__(self):
        loop = asyncio.get_running_loop()
        while True:
            async with self.cond:
                await self.cond.wait_for(lambda: self.in_flight < self.limit)
                delay = self.pause_until - loop.time()
                if delay <= 0:
                    self.in_flight += 1
                    return self
            await asyncio.sleep(delay)  # the host asked for a pause: wait outside the lock

    async def __aexit__(self, *exc):
        async with self.cond:
            self.in_flight -= 1
            self.cond.notify_all()

    def record(self, status, retry_after=None):
        if status in (429, 503):
            self.limit, self.clean = max(self.low, self.limit // 2), 0
            wait = int(retry_after) if retry_after and retry_after.isdigit() else 5 + random.random()
            now = asyncio.get_running_loop().time()
            self.pause_until = max(self.pause_until, now + wait)
        elif status < 400:
            self.clean += 1
            if self.clean >= 20 and self.limit < self.high:
                self.limit, self.clean = self.limit + 1, 0


gates = {}


def gate_for(url):
    host = urlsplit(url).hostname
    if host not in gates:
        gates[host] = AdaptiveLimit()
    return gates[host]


async def fetch(client, url, attempts=2):
    gate = gate_for(url)
    status = None
    for _ in range(attempts):
        try:
            async with gate:
                r = await client.get(url)
        except httpx.HTTPError as exc:
            return "error: %s" % type(exc).__name__
        status = r.status_code
        gate.record(status, r.headers.get("Retry-After"))
        if status not in (429, 503):
            break  # the retry, if any, waits for the host's pause in __aenter__
    return status


async def main(urls):
    timeout = httpx.Timeout(30.0, connect=10.0)
    async with httpx.AsyncClient(proxy=PROXY, timeout=timeout) as client:
        print(await asyncio.gather(*(fetch(client, u) for u in urls)))
    print({host: gate.limit for host, gate in gates.items()})


asyncio.run(main(["https://example.com/"] * 10))

대상 외에 프록시 크롤링 속도를 느리게 하는 원인은?

  • TLS 핸드셰이크. 매 요청마다 새 연결을 생성하면(새 IP가 필요할 때) 사이트와 매번 핸드셰이크가 발생합니다. IP 다양성이 중요하지 않다면 하나 사이트 내 여러 페이지에서 지속 연결(keep-alive)로 세션 유지하세요.
  • 느린 출구. 레지덴셜 프록시와 4G 모바일 프록시는 실제 가정 및 셀룰러 링크입니다. 타임아웃과 새 연결 재시도를 사용하세요.
  • 좁은 타깃팅. 소도시나 단일 ASN은 국가보다 출구가 적습니다. 데이터가 변할 때만 좁게 타깃팅하세요.
  • 렌더링. 헤드리스 브라우저는 HTTP 클라이언트보다 페이지당 CPU, 메모리, 트래픽 비용이 훨씬 높습니다. 자바스크립트가 필요한 페이지만 렌더링하세요.
  • DNS. socks5h:// 또는 HTTP 포트로 DNS는 출구에서 해석됩니다; 대상 호스트에 로컬 DNS 캐시가 필요 없습니다.

동시성 관련 질문

CrawlRelay가 스레드나 연결 수를 제한하나요?

요금제는 트래픽 GB당 청구되며, 스레드, 연결, 요청당 청구가 아니며 공개 요금제에는 스레드 수 제한이 없습니다. 실질적 제한은 각 대상의 허용치와 자신의 기기 능력입니다. 대규모 크롤링 계획 시 [email protected]에 먼저 문의해 타깃 커버리지를 확인하세요.

스레드를 더 추가하니 크롤이 느려진 이유는?

대부분 대상이 제한을 걸기 시작했기 때문입니다: 응답 시간이 늘고 429 또는 503 응답이 나타나며 재시도가 부하를 가중시킵니다. 또 다른 원인은 헤드리스 브라우저를 쓴 기기의 CPU 또는 소켓 부족입니다. 스레드 추가 전 호스트별 지연과 오류율을 측정하세요.

요청당 한 연결이 keep-alive보다 느린가요?

네, 요청마다 TCP와 TLS 핸드셰이크가 추가되어 일반적으로 레지덴셜 프록시 출구에서 수백 밀리초 지연됩니다. 이는 매 요청마다 새 IP를 쓰는 대가입니다. IP가 중요하지 않은 동일 사이트 내 다수 페이지에는 지속 연결이 더 빠르고 트래픽도 적게 씁니다.

병렬 크롤러에서 robots.txt의 crawl-delay를 어떻게 준수하나요?

호스트당 robots.txt를 한 번 파싱하고, RFC 9309 권고처럼 최대 24시간 캐시하며, Crawl-delay 값을 각 호스트별 요청 최소 간격(동시성 1 기준)으로 변환하세요. Python의 urllib.robotparser는 이를 crawl_delay()에 노출합니다.

GB당 과금으로 확장하세요

US$0.50/GB에서 50 GB에서 1 TB까지, 만료 없는 트래픽.

US$0.50/GB 부터 · KYC 없이

시작하기