ওয়েব স্ক্র্যাপিং এবং এজেন্ট

AI ক্রলার এবং এজেন্টে HTTP 429 ও Cloudflare 520 ত্রুটি সমাধানের পূর্ণাঙ্গ গাইড

দ্রুত উত্তর: HTTP 429 ত্রুটি লক্ষ্য API বা WAF-এর রেট লিমিট অতিক্রম নির্দেশ করে, যা ডিকরিলেটেড জিটার (Decorrelated Jitter) ব্যাকঅফ এবং রোটেটিং রেসিডেন্সিয়াল প্রক্সি দিয়ে সমাধান করা যায়। অন্যদিকে Cloudflare 520 ত্রুটি ("Web Server Returned an Unknown Error") ক্রলারের অতিরিক্ত চাপে অরিজিন সার্ভার ক্র্যাশ বা অসম্পূর্ণ TCP RST রেসপন্স পাঠালে তৈরি হয়। Keep-Alive টিউনিং ও সার্কিট ব্রেকার প্যাটার্ন দ্বারা এটি প্রতিহত করা হয়।

1. ভূমিকা: স্বায়ত্তশাসিত AI ওয়েব ক্রলারের দুর্বলতা

AI এজেন্ট যখন চ্যাটবট থেকে রিয়েল-টাইম মাল্টি-স্টেপ রিজনিং ইঞ্জিনে রূপান্তরিত হচ্ছে, তখন প্রধান বাধা হয়ে দাঁড়িয়েছে নেটওয়ার্ক নির্ভরযোগ্যতা ও এজ অ্যাক্সেস

উৎপাদনশীল এজেন্টরা প্রতি মিনিটে হাজার হাজার HTTP কল পাঠায়। প্রথাগত স্ক্র্যাপারের তুলনায় AI এজেন্টের প্রয়োজন:

  1. রিজনিং লুপ চালু রাখতে স্বল্প বিলম্বের সিঙ্ক্রোনাস ডেটা সংগ্রহ
  2. SPA সাইট লোড করতে নিখুঁত জাভাস্ক্রিপ্ট সম্পাদন
  3. টোকেন বাঁচাতে পরিচ্ছন্ন মার্কডাউন রূপান্তর

কিন্তু Cloudflare ও DataDome-এর মতো এজ প্ল্যাটফর্মের কারণে দুটি প্রধান ত্রুটির সম্মুখীন হতে হয়:

  • HTTP 429 Too Many Requests: নির্দিষ্ট সময়ে অতিরিক্ত রিকোয়েস্ট পাঠানো।
  • HTTP 520 Web Server Returned an Unknown Error: অরিজিন সার্ভার ক্লাউডফ্লেয়ারের কাছে ত্রুটিপূর্ণ রেসপন্স পাঠালে এই সমস্যা হয়।

2. HTTP 429 ত্রুটির বিশ্লেষণ

HTTP 429 ত্রুটি মূলত তিনটি স্তরে উৎপন্ন হয়:

  1. লেভেল ১: এজ WAF (Cloudflare / DataDome): Python OpenSSL-এর JA4 ফিঙ্গারপ্রিন্ট এবং Chrome User-Agent-এর গরমিল ধরা পড়লে সরাসরি 429 বা ক্যাপচা প্রদান করে।
  2. লেভেল ২: API গেটওয়ে (Kong, Envoy, Nginx): টোকেন বাকেট (Token Bucket) ও লিকি বাকেট অ্যালগরিদম।
  3. লেভেল ৩: অরিজিনাল সার্ভার: ডাটাবেস বা মেমরি ওভারলোড প্রতিরোধ।

পরীক্ষণীয় হেডারসমূহ: Retry-After, RateLimit-Limit, RateLimit-Remaining, ও RateLimit-Reset


3. Cloudflare 520 ত্রুটির কারণ

520 কোডটি ক্লাউডফ্লেয়ারের নিজস্ব এবং এটি অরিজিন সার্ভারের ব্যর্থতা নির্দেশ করে:

  1. প্রসেস ক্র্যাশ (OOM / SIGSEGV): অতিরিক্ত রিকোয়েস্টের কারণে সার্ভার মেমরি শেষ হয়ে TCP RST প্যাকেট প্রেরণ করে।
  2. Keep-Alive টাইমআউট অমিল: Cloudflare 15 সেকেন্ড কানেকশন রাখে, কিন্তু Nginx সার্ভার 5 সেকেন্ডে বন্ধ করলে 520 তৈরি হয়।
  3. হেডার বাফার ওভারফ্লো (>16KB): অতিরিক্ত কুকি ক্লাউডফ্লেয়ারের সীমা অতিক্রম করে।
  4. শূন্য বাইট রেসপন্স: কোনো ডেটা না পাঠিয়ে কানেকশন বন্ধ হওয়া।

4. অ্যালগরিদমিক সমাধান: Decorrelated Jitter ও সার্কিট ব্রেকার

গতানুগতিক রি-ট্রাই লুপ সার্ভারকে আরও বিপর্যস্ত করে তোলে। AWS আর্কিটেকচারের সবচেয়ে নির্ভরযোগ্য সমাধান হলো ডিকরিলেটেড জিটার (Decorrelated Jitter):

# Decorrelated Jitter সূত্র:
sleep = min(cap, random.uniform(base, previous_delay * 3.0))

সার্কিট ব্রেকারযুক্ত Python স্ক্রিপ্ট

import asyncio, random, time, aiohttp
from urllib.parse import urlparse

class ResilientAgentCrawler:
    def __init__(self, base_delay=1.0, max_delay=60.0, max_retries=5, threshold=4, cooldown=30.0):
        self.base_delay = base_delay
        self.max_delay = max_delay
        self.max_retries = max_retries
        self.threshold = threshold
        self.cooldown = cooldown
        self.failures = {}
        self.opened_at = {}

    def _is_open(self, domain):
        t = self.opened_at.get(domain)
        if not t: return False
        if time.monotonic() - t > self.cooldown:
            del self.opened_at[domain]
            self.failures[domain] = 0
            return False
        return True

    async def fetch(self, session, url):
        domain = urlparse(url).netloc
        if self._is_open(domain):
            raise RuntimeError(f"সার্কিট ব্রেকার খোলা রয়েছে: {domain}")

        delay = self.base_delay
        for attempt in range(1, self.max_retries + 1):
            try:
                async with session.get(url) as resp:
                    if resp.status == 200:
                        self.failures[domain] = 0
                        return await resp.text()
                    elif resp.status == 429:
                        retry_after = resp.headers.get("Retry-After")
                        wait = float(retry_after) if retry_after else random.uniform(self.base_delay, delay * 3.0)
                        delay = min(self.max_delay, wait)
                        await asyncio.sleep(delay)
                    elif resp.status in (520, 502, 503, 504):
                        self.failures[domain] = self.failures.get(domain, 0) + 1
                        if self.failures[domain] >= self.threshold:
                            self.opened_at[domain] = time.monotonic()
                        delay = min(self.max_delay, random.uniform(self.base_delay, delay * 3.0))
                        await asyncio.sleep(delay)
                    else:
                        resp.raise_for_status()
            except Exception as e:
                if attempt == self.max_retries: raise e
                await asyncio.sleep(delay)

5. TLS JA4 ফিঙ্গারপ্রিন্ট বাইপাস (curl_cffi)

২০২৬ সালে শুধু User-Agent পরিবর্তন করে রেহাই পাওয়া অসম্ভব। curl_cffi ব্যবহার করে Chrome-এর সমতুল্য TLS ও HTTP/2 সেটিংস অনুকরণ করুন:

from curl_cffi.requests import AsyncSession

async def fetch_stealth(url: str):
    async with AsyncSession(impersonate="chrome124") as s:
        res = await s.get(url, timeout=15)
        return res.text

6. প্রক্সি নেটওয়ার্ক ও সার্ভার কনফিগারেশন

  • রোটেটিং রেসিডেন্সিয়াল প্রক্সি: বিভিন্ন গৃহস্থালি আইপি ব্যবহারের মাধ্যমে 429 রেট লিমিট এড়ানো যায়।
  • মোবাইল প্রক্সি (4G/5G CGNAT): এক আইপি হাজার হাজার ব্যবহারকারী শেয়ার করায় WAF ব্লক এড়ানোর সর্বোচ্চ ক্ষমতা রাখে।
  • Nginx সার্ভার কনফিগারেশন:
http {
    keepalive_timeout 75s;
    keepalive_requests 10000;
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
}

7. উপসংহার

AI ক্রলারের নিরবচ্ছিন্ন কার্যকারিতা নিশ্চিত করতে:

  1. Decorrelated Jitter ব্যবহার করুন।
  2. curl_cffi দিয়ে ব্রাউজার ফিঙ্গারপ্রিন্ট অনুকরণ করুন।
  3. অরিজিন সার্ভারের Keep-Alive সময় ৭৫ সেকেন্ড নির্ধারণ করুন।
  4. সার্কিট ব্রেকার দিয়ে LLM টোকেন বাজেট রক্ষা করুন।
← সব নিবন্ধ
0 / 4